Need help to deal with Photo for Xamarin forms - azure

I am using xamarin forms. I want to pick photo from gallery for my iphone app and want to save it in Azure DB. Is there any solution available for xamarin forms. Or Is there any plugin available to deal with Photo, Document, or Audio. Any help is appreciated.

Using dependency service you can take or pick photos from Android / iPhone :-
Please refer to code below and try to implement the similar code:-
This is the interface in PCL:-
public interface IGalleryProvider
{
Task<List<AttachmentMediaFile>> PickPhotoAsync();
Task<List<AttachmentMediaFile>> PickAudioAsync();
Task<List<AttachmentMediaFile>> PickDocumentAsync();
Task<AttachmentMediaFile> PickProfilePhotoAsync();
Task SaveToGalleryAsync(AttachmentMediaFile file);
}
Below is the code using which you can pick or take photos from iPhone only:-
using AssetsLibrary;
using AVFoundation;
using ELCImagePicker;
using Foundation;
using MediaPlayer;
using MobileCoreServices;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UIKit;
[assembly: Xamarin.Forms.Dependency(typeof(GalleryProvider))]
namespace SanketSample.MobileApp.Sample.iOS.Common
{
public class GalleryProvider : IGalleryProvider
{
private TaskCompletionSource<List<AttachmentMediaFile>> _audioPickedTask;
public async Task<List<AttachmentMediaFile>> PickAudioAsync()
{
_audioPickedTask = new TaskCompletionSource<List<AttachmentMediaFile>>();
var picker = new MPMediaPickerController();
ShowViewController(picker);
picker.ItemsPicked += OnAudioPicked;
picker.DidCancel += OnCancel;
var media = await _audioPickedTask.Task;
return media;
}
private void OnCancel(object sender, EventArgs e)
{
var picker = sender as MPMediaPickerController;
picker.DidCancel -= OnCancel;
picker.DismissViewController(true, null);
_audioPickedTask.TrySetResult(new List<AttachmentMediaFile>());
}
private void OnAudioPicked(object sender, ItemsPickedEventArgs e)
{
var media = new List<AttachmentMediaFile>();
var picker = sender as MPMediaPickerController;
picker.ItemsPicked -= OnAudioPicked;
picker.DismissViewController(true, null);
if (e.MediaItemCollection.Items != null)
{
foreach (var item in e.MediaItemCollection.Items)
{
//var vm1 = (new ViewModelLocator()).AttachmentsVM.SelectedAttachments.Add();
if (!item.IsCloudItem)
{
try
{
//var error = new NSError();
//var asset = new AVUrlAsset(item.AssetURL);
//var exporter = new AVAssetExportSession(asset, item.Title);
//exporter.OutputFileType = "com.apple.m4a-audio";
//AVAssetExportSession session = new AVAssetExportSession(asset, "");
//var reader = new AVAssetReader(asset, out error);
//var settings = new NSDictionary();
//Func<byte[]> bytesGetter = e.MediaItemCollection
//TODO item.Title, item.Title SSSanket,
//var _asset = AVAsset.FromUrl(NSUrl.FromFilename(item.AssetURL.ToString()));
//var _exportSession = new AVAssetExportSession(_asset, AVAssetExportSession.PresetPassthrough);
//_exportSession.OutputFileType = AVFileType.Aiff;
// media.Add(new AttachmentMediaFile(item.AssetURL.AbsoluteString, AttachmentMediaFileType.Audio, null , item.Title));
}
catch (Exception ex)
{
// throw ;
}
}
}
}
_audioPickedTask.TrySetResult(media);
}
public async Task<List<AttachmentMediaFile>> PickDocumentAsync()
{
var task = new TaskCompletionSource<List<AttachmentMediaFile>>();
var allowedUTIs = new string[]
{
UTType.UTF8PlainText,
UTType.PlainText,
UTType.RTF,
UTType.Text,
UTType.PDF,
"com.microsoft.word.doc",
"com.microsoft.excel.xls"
};
var pickerMenu = new UIDocumentMenuViewController(allowedUTIs, UIDocumentPickerMode.Open);
pickerMenu.DidPickDocumentPicker += (sender, args) =>
{
args.DocumentPicker.DidPickDocument += (sndr, pArgs) =>
{
var securityEnabled = pArgs.Url.StartAccessingSecurityScopedResource();
NSError err;
var fileCoordinator = new NSFileCoordinator();
var docs = new List<AttachmentMediaFile>();
// Read bytes.
fileCoordinator.CoordinateRead(pArgs.Url, 0, out err, (NSUrl newUrl) =>
{
NSData data = NSData.FromUrl(newUrl);
docs.Add(new AttachmentMediaFile(pArgs.Url.AbsoluteString, AttachmentMediaFileType.Doc, data.ToArray(),null));
task.TrySetResult(docs);
});
};
ShowViewController(args.DocumentPicker);
};
ShowViewController(pickerMenu);
return await task.Task;
}
public async Task<List<AttachmentMediaFile>> PickPhotoAsync()
{
var media = new List<AttachmentMediaFile>();
var picker = ELCImagePickerViewController.Instance;
picker.MaximumImagesCount = 15;
ShowViewController(picker);
await picker.Completion.ContinueWith(result =>
{
picker.BeginInvokeOnMainThread(() =>
{
picker.DismissViewController(true, null);
if (!result.IsCanceled && result.Exception == null)
{
var imageEditor = new ImageEditor();
var items = result.Result as List<AssetResult>;
foreach (var item in items)
{
var bbytes= imageEditor.ResizeImage(item.Image, 1024, 1024);
media.Add(new AttachmentMediaFile(item.Path, AttachmentMediaFileType.Photo, bbytes, item.Name));
}
}
});
});
return media;
}
public async Task<AttachmentMediaFile> PickProfilePhotoAsync()
{
AttachmentMediaFile selectMediaFile = null;
var picker = ELCImagePickerViewController.Instance;
picker.MaximumImagesCount = 1;
ShowViewController(picker);
await picker.Completion.ContinueWith(result =>
{
picker.BeginInvokeOnMainThread(() =>
{
picker.DismissViewController(true, null);
if (!result.IsCanceled && result.Exception == null)
{
var imageEditor = new ImageEditor();
var items = result.Result as List<AssetResult>;
foreach (var item in items)
{
var bbytes = imageEditor.ResizeImage(item.Image, 1024, 1024);
selectMediaFile = new AttachmentMediaFile(item.Path, AttachmentMediaFileType.Photo, bbytes, item.Name);
}
}
});
});
return selectMediaFile;
}
public async Task SaveToGalleryAsync(AttachmentMediaFile file)
{
var bytes = file.GetBytes();
var originalImage = ImageEditor.ImageFromByteArray(bytes);
var library = new ALAssetsLibrary();
var orientation = (ALAssetOrientation)originalImage.Orientation;
var nsUrl = await library.WriteImageToSavedPhotosAlbumAsync(originalImage.CGImage, orientation);
}
private void ShowViewController(UIViewController controller)
{
var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (topController.PresentedViewController != null)
{
topController = topController.PresentedViewController;
}
topController.PresentViewController(controller, true, null);
}
}
}
Below are useful classes :-
public class AttachmentMediaFile
{
private readonly Func<byte[]> _bytesGetter;
public string LocalPath { get; private set; }
public string Name { get; private set; }
public AttachmentMediaFileType Type { get; private set; }
public AttachmentMediaFile(string localPath, AttachmentMediaFileType type, byte[] bytesGetter, string name = null)
{
LocalPath = localPath;
Type = type;
_bytesGetter = () =>
{
return bytesGetter;
};
if (string.IsNullOrEmpty(name))
{
Name = FileNameHelper.PrepareName(localPath);
}
else
{
Name = name;
}
}
public byte[] GetBytes()
{
return _bytesGetter();
}
}
public enum AttachmentMediaFileType
{
Photo = 0,
Audio = 1,
Doc = 2,
Video = 3,
}
public static class FileNameHelper
{
private const string Prefix = "IMG";
public static string PrepareName(string localPath)
{
var name = string.Empty;
if (!string.IsNullOrEmpty(localPath))
{
name = localPath.Split('/').Last();
}
return name;
}
public static string GenerateUniqueFileName(Extension extension)
{
var format = ".jpg";
var fileName = string.Concat(Prefix, '_', DateTime.UtcNow.Ticks, format);
return fileName;
}
public enum Extension
{
JPG
}
}
Now if you want to store your data to Azure Server Table so you are already using Azure mobile service client SDK similarly you need Blob nuget from Azure using which you can save your photos by making blob objects to Azure server :-
use blob helper nuget from manage nuget package install Microsoft.WindowsAzure.Storage.Auth;
Microsoft.WindowsAzure.Storage.Blob;
this and try to implement the code similarly I given bellow:-
using Acr.UserDialogs;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using SanketSample.MobileApp.sample.Business.Azure;
using SanketSample.MobileApp.sample.Business.Interfaces;
using SanketSample.MobileApp.sample.Models;
using SanketSample.MobileApp.sample.Models.AzureTables;
using SanketSample.MobileApp.sample.Models.Media;
using SanketSample.MobileApp.sample.Utils;
using Xamarin.Forms;
namespace SanketSample.MobileApp.Sanket.Common.Media
{
public class BlobHelper
{
private const string ContainerName = "attachments";
private Dictionary<string, TaskCompletionSource<bool>> _tasks;
private IHttpService _httpservice { get; set; }
#region Singleton Implementation
private static readonly Lazy<BlobHelper> lazyInstance = new Lazy<BlobHelper>(() => new BlobHelper(), true);
private BlobHelper()
{
_tasks = new Dictionary<string, TaskCompletionSource<bool>>();
}
public static BlobHelper Instance
{
get { return lazyInstance.Value; }`enter code here`
}
#endregion Singleton Implementation
public async Task UploadAttachments(IList<AttachmentFile> attachments, long associatedRecordId, string category)
{
foreach (var attachment in attachments)
{
await UploadAttachment(attachment, associatedRecordId, category);
}
}
public async Task UploadAttachment(AttachmentFile attachment, long associatedRecordId, string category)
{
try
{
CommonHelper commonHelper = new CommonHelper();
attachment.ContainerName = ContainerName;
attachment.AssociatedRecordId = associatedRecordId;
//attachment.RecordId = commonHelper.GenerateRecordId();
if (attachment.FileExtension == null)
{
attachment.FileExtension = ConvertType(attachment.MediaFile);
}
attachment.Category = category;
var taskCompletionSource = new TaskCompletionSource<bool>();
if (!_tasks.ContainsKey(attachment.Name))
{ _tasks.Add(attachment.Name, taskCompletionSource); }
else
{
_tasks[attachment.Name] = taskCompletionSource;
}
// _tasks.Add(attachment.Name, taskCompletionSource);
var attachmentsTableOnline = AzureServiceProvider.Instance.GetRemoteTable<AttachmentFile>();
if (CheckInternetConnection.IsConnected())
{
await attachmentsTableOnline.InsertAsync(attachment);
}
var attachmentsTableOffline = AzureServiceProvider.Instance.GetLocalTable<AttachmentFile>();
await attachmentsTableOffline.InsertAsync(attachment);
if (!string.IsNullOrEmpty(attachment.SasQueryString))
{
var credentials = new StorageCredentials(attachment.SasQueryString);
var imageUri = new Uri(attachment.Uri);
var container = new CloudBlobContainer(new Uri(string.Format("https://{0}/{1}",
imageUri.Host, attachment.ContainerName)), credentials);
var blobFromSASCredential = container.GetBlockBlobReference(attachment.Name);
try
{
var bytes = attachment.MediaFile.GetBytes();
await blobFromSASCredential.UploadFromByteArrayAsync(bytes, 0, bytes.Length);
if (CheckInternetConnection.IsConnected())
{
await attachmentsTableOnline.UpdateAsync(attachment);
}
await attachmentsTableOffline.UpdateAsync(attachment);
taskCompletionSource.TrySetResult(true);
}
catch (Microsoft.WindowsAzure.Storage.StorageException ex)
{
// Throws from UploadFromByteArrayAsync, but image uploaded.
System.Diagnostics.Debug.WriteLine($"BlobHelper: {ex}");
taskCompletionSource.TrySetResult(true);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"BlobHelper: {ex}");
taskCompletionSource.TrySetResult(false);
}
}
}
catch (Exception ca)
{
//throw ca;
}
}
/// <summary>
/// Downloads Blob Data boject and returns the Byts[] data
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public async Task<byte[]> DownloadAttachment(AttachmentFile file)
{
byte[] bytes = null;
var fileContainer = file.Uri.Replace(file.Name, string.Empty);
var container = new CloudBlobContainer(new Uri(fileContainer));
var blob = container.GetBlockBlobReference(file.Name);
using (var stream = new MemoryStream())
{
var isExist = await blob.ExistsAsync();
if (isExist)
{
await blob.DownloadToStreamAsync(stream);
bytes = stream.ToArray();
}
}
return bytes;
}
/// <summary>
/// Updates the Attachments Byts in the Azure Local Tables.
/// </summary>
/// <param name="AttachmentFileRecordId">Attachments Byte[] Data.</param>
/// <returns></returns>
public async Task<byte[]> DownloadAttachmentFileDetails(long? AttachmentFileRecordId, IHttpService service)
{
_httpservice = service;
try
{
ResponseWrapper<AttachmentFileDetail> result = new ResponseWrapper<AttachmentFileDetail>();
if (AttachmentFileRecordId != null)
{
var request = Constants.API_BASE_URL + string.Format(Constants.API_ATTACHMENTS_PARAMETERS, AttachmentFileRecordId);
var response = await _httpservice.SendRequestAsync(HttpMethod.Get, request);
result.Status = response.Status;
if (response.IsSuccess)
{
result.Result = JsonConvert.DeserializeObject<AttachmentFileDetail>(response.Result);
if (result.Result == null)
{
result.Status = System.Net.HttpStatusCode.InternalServerError;
}
else
{
var output = result.Result;
var data = new List<AttachmentFileDetail>() { output };
await AzureServiceProvider.Instance.DatabaseService.InsertDataToLocalDB<AttachmentFileDetail>(data);
return result.Result.FileByteArray;
}
}
}
}
catch (Exception ex)
{
////throw ex;
}
finally
{
}
return null;
}
private string ConvertType(AttachmentMediaFile file)
{
switch (file.Type)
{
case AttachmentMediaFileType.Doc:
return "doc";
case AttachmentMediaFileType.Audio:
return "mp3";
}
return "jpeg";
}
}
}

media plugin on github
works pretty well for me.

Related

Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: Access denied

I encountered an exception when I used c# code to create subdirectories in sharepoint's specified directory.
Exception message:
Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: Access denied. You do not have permission to perform this action or access this resource.
Anybody can help me? thanks!
The following is parameters:
file: D:\Repos\helpfilesync\ArtefactUploader\bin\Release\ArtefactUploader.exe
fileName: ArtefactUploader.exe
uploadPath: /sites/Platform/Shared Documents/dailybuild/helpfilesync/
subFolderPath: v0.1.0/
public void Upload()
{
using (ClientContext clientContext = new ClientContext("*****"))
{
SecureString pass = new SecureString();
foreach (char ch in password)
{
pass.AppendChar(ch);
}
clientContext.Credentials = new SharePointOnlineCredentials(user, pass);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
if (!string.IsNullOrWhiteSpace(this.subFolderPath))
{
CreateFolder(clientContext.Web, uploadPath, subFolderPath);
}
using (FileStream fs = new FileStream(file, FileMode.Open))
{
Microsoft.SharePoint.Client.File.SaveBinaryDirect
(clientContext, $"{this.uploadPath}{this.subFolderPath}/{fileName}", fs, true);
}
Console.WriteLine("Uploaded File Successfully");
}
}
public void CreateFolder(Web web, string relativePath, string fullFolderPath)
{
if (web == null)
{
throw new ArgumentNullException(nameof(web));
}
if (string.IsNullOrWhiteSpace(relativePath))
{
throw new ArgumentNullException(nameof(relativePath));
}
if (string.IsNullOrWhiteSpace(fullFolderPath))
{
throw new ArgumentNullException(fullFolderPath);
}
Folder relativeFolder = web.GetFolderByServerRelativeUrl(relativePath);
CreateFolderInternal(web, relativeFolder, fullFolderPath);
}
public static Folder CreateFolderInternal(Web web, Folder parentFolder, string fullFolderPath)
{
var folderUrls = fullFolderPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string folderUrl = folderUrls[0];
var curFolder = parentFolder.Folders.Add(folderUrl);
//web.Context.Load(curFolder);
try
{
web.Context.ExecuteQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
if (folderUrls.Length > 1)
{
var folderPath = string.Join("/", folderUrls, 1, folderUrls.Length - 1);
return CreateFolderInternal(web, curFolder, folderPath);
}
return curFolder;
}
Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: Access
denied. You do not have permission to perform this action or access
this resource. at
Microsoft.SharePoint.Client.ClientRequest.ProcessResponseStream(Stream
responseStream) at
Microsoft.SharePoint.Client.ClientRequest.ProcessResponse() at
Microsoft.SharePoint.Client.ClientContext.ExecuteQuery() at
ArtefactUploader.SharepointUploader.CreateFolderInternal(Web web,
Folder parentFolder, String fullFolderPath) in
D:\Repos\helpfilesync\ArtefactUploader\SharepointUploader.cs:line 96
Did test of your code, works fine. Make sure the user/password is correct.
class Program
{
const string user = "user#teanat.onmicrosoft.com";
const string password = "password";
public static void Upload()
{
using (ClientContext clientContext = new ClientContext("https://tenant.sharepoint.com/sites/lee"))
{
SecureString pass = new SecureString();
foreach (char ch in password)
{
pass.AppendChar(ch);
}
clientContext.Credentials = new SharePointOnlineCredentials(user, pass);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
if (!string.IsNullOrWhiteSpace("a"))
{
CreateFolder(clientContext.Web, "/sites/lee/mydoc2", "childA");
}
//using (FileStream fs = new FileStream(file, FileMode.Open))
//{
// Microsoft.SharePoint.Client.File.SaveBinaryDirect
// (clientContext, $"{this.uploadPath}{this.subFolderPath}/{fileName}", fs, true);
//}
Console.WriteLine("Uploaded File Successfully");
}
}
public static void CreateFolder(Web web, string relativePath, string fullFolderPath)
{
if (web == null)
{
throw new ArgumentNullException(nameof(web));
}
if (string.IsNullOrWhiteSpace(relativePath))
{
throw new ArgumentNullException(nameof(relativePath));
}
if (string.IsNullOrWhiteSpace(fullFolderPath))
{
throw new ArgumentNullException(fullFolderPath);
}
Folder relativeFolder = web.GetFolderByServerRelativeUrl(relativePath);
CreateFolderInternal(web, relativeFolder, fullFolderPath);
}
public static Folder CreateFolderInternal(Web web, Folder parentFolder, string fullFolderPath)
{
var folderUrls = fullFolderPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string folderUrl = folderUrls[0];
var curFolder = parentFolder.Folders.Add(folderUrl);
//web.Context.Load(curFolder);
try
{
web.Context.ExecuteQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
if (folderUrls.Length > 1)
{
var folderPath = string.Join("/", folderUrls, 1, folderUrls.Length - 1);
return CreateFolderInternal(web, curFolder, folderPath);
}
return curFolder;
}
static void Main(string[] args)
{
Upload();
}
}

Azure Table Storage not saving all object properties

I have a problem with the Azure Table Storage. What I'm trying to achieve is saving the ChangeToken of the SharePoint list in order to use the webhooks properly.
Here is the code:
public class TablesHelper
{
private static readonly string TokenTableName = "TokenTable";
public static async Task<ListChangeToken> GetChangeTokenForListAsync(string listId)
{
var retrieveOperation = TableOperation.Retrieve<ListChangeToken>("Lists", listId, new List<string>() { "ChangeToken" });
var tableReference = await GetTableReferenceAsync(TokenTableName);
var tableResult = await tableReference.ExecuteAsync(retrieveOperation);
if(tableResult.Result != null)
{
return tableResult.Result as ListChangeToken;
}
return null;
}
public static async Task SaveChangeTokenForListAsync(ListChangeToken changeToken)
{
var insertOperation = TableOperation.Insert(changeToken);
var tableReference = await GetTableReferenceAsync(TokenTableName);
var result = await tableReference.ExecuteAsync(insertOperation);
}
private static async Task<CloudTable> GetTableReferenceAsync(string tableName)
{
var storageAccount = CloudStorageAccount.Parse(ConfigurationHelper.CloudStorage);
var tableClient = storageAccount.CreateCloudTableClient();
var reference = tableClient.GetTableReference(tableName);
await reference.CreateIfNotExistsAsync();
return reference;
}
}
The ListChangeToken class:
public class ListChangeToken : TableEntity
{
public ListChangeToken(string listId, string changeToken)
{
this.PartitionKey = "Lists";
this.RowKey = listId;
this.ChangeToken = changeToken;
}
public ListChangeToken() { }
public string ChangeToken { get; set;}
}
As per request, the function calling TablesHelper:
[FunctionName("EventHandler")]
public static async Task Run([QueueTrigger("events", Connection = "CloudStorage")]string myQueueItem, TraceWriter log)
{
var notificationGroup = Newtonsoft.Json.JsonConvert.DeserializeObject<NotificationGroup>(myQueueItem);
var contextHelper = new ContextHelper();
foreach (var notification in notificationGroup.Value)
{
UriBuilder uriBuilder = new UriBuilder();
uriBuilder.Scheme = "https";
uriBuilder.Host = ConfigurationHelper.TenantDomain;
uriBuilder.Path = notification.SiteUrl;
using (var ctx = contextHelper.GetAppOnlyContext(uriBuilder.ToString()))
{
//Read change token
var currentChangeToken = await TablesHelper.GetChangeTokenForListAsync(notification.Resource);
if(currentChangeToken == null)
{
log.Error($"No change token found for list {notification.Resource}. This is a NO GO. Please use the '/api/Setup' function.");
}
var listId = Guid.Parse(notification.Resource);
var changes = await CSOMHelper.GetListItemChangesAsync(ctx, listId, currentChangeToken.ChangeToken);
if(changes.Count > 0)
{
var lastChange = changes[changes.Count - 1];
//Save the last change token
var changeTokenValue = lastChange.ChangeToken.StringValue;
await TablesHelper.SaveChangeTokenForListAsync(new ListChangeToken(
notification.Resource,
changeTokenValue
));
await HandleChanges(ctx, changes);
}
}
}
log.Info($"C# Queue trigger function processed: {myQueueItem}");
}
The problem is that always, when using the "GetChangeTokenForListAsync" the Entity is received properly, but the .ChangeToken property is always null. It is also not visible when browsing with the Azure Storage Explorer. What am I doing wrong here?
The issue is related to the Azure Storage Emulator (V. 5.7.0.0). The same code works perfectly when working with the "live" Azure.

Xamarin IOS file picker : unable to get selected file from icloud drive

I've installed filepicker control from Nuget and added tried adding reference from MonoTouch10 folder and later from github to my xamarin.ios project.
FileData file = await CrossFilePicker.Current.PickFile();
if (file != null) { }
this is the code i added to my browse button, after selecting a file from iCloud drive, control never comes to "if condition".
and again when i click on browse button for second time, app crashes saying "only one operation can be active at a time".
Modifying the source code of the FilePickerImplementation plugin for the iOS platform worked, in this way:
using Foundation;
using MobileCoreServices;
using Plugin.FilePicker.Abstractions;
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using UIKit;
using System.Diagnostics;
namespace Plugin.FilePicker
{
/// <summary>
/// Implementation for FilePicker
/// </summary>
public class FilePickerImplementation : NSObject, IUIDocumentMenuDelegate, IFilePicker
{
private int _requestId;
private TaskCompletionSource<FileData> _completionSource;
/// <summary>
/// Event which is invoked when a file was picked
/// </summary>
public EventHandler<FilePickerEventArgs> Handler
{
get;
set;
}
private void OnFilePicked(FilePickerEventArgs e)
{
Handler?.Invoke(null, e);
}
public void DidPickDocumentPicker(UIDocumentMenuViewController documentMenu, UIDocumentPickerViewController documentPicker)
{
documentPicker.DidPickDocument += DocumentPicker_DidPickDocument;
documentPicker.WasCancelled += DocumentPicker_WasCancelled;
documentPicker.DidPickDocumentAtUrls += DocumentPicker_DidPickDocumentAtUrls;
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(documentPicker, true, null);
}
private void DocumentPicker_DidPickDocumentAtUrls(object sender, UIDocumentPickedAtUrlsEventArgs e)
{
var control = (UIDocumentPickerViewController)sender;
foreach (var url in e.Urls)
DocumentPicker_DidPickDocument(control, new UIDocumentPickedEventArgs(url));
control.Dispose();
}
private void DocumentPicker_DidPickDocument(object sender, UIDocumentPickedEventArgs e)
{
var securityEnabled = e.Url.StartAccessingSecurityScopedResource();
var doc = new UIDocument(e.Url);
var data = NSData.FromUrl(e.Url);
var dataBytes = new byte[data.Length];
System.Runtime.InteropServices.Marshal.Copy(data.Bytes, dataBytes, 0, Convert.ToInt32(data.Length));
string filename = doc.LocalizedName;
string pathname = doc.FileUrl?.ToString();
// iCloud drive can return null for LocalizedName.
if (filename == null)
{
// Retrieve actual filename by taking the last entry after / in FileURL.
// e.g. /path/to/file.ext -> file.ext
// filesplit is either:
// 0 (pathname is null, or last / is at position 0)
// -1 (no / in pathname)
// positive int (last occurence of / in string)
var filesplit = pathname?.LastIndexOf('/') ?? 0;
filename = pathname?.Substring(filesplit + 1);
}
OnFilePicked(new FilePickerEventArgs(dataBytes, filename, pathname));
}
/// <summary>
/// Handles when the file picker was cancelled. Either in the
/// popup menu or later on.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DocumentPicker_WasCancelled(object sender, EventArgs e)
{
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs.SetResult(null);
}
}
/// <summary>
/// Lets the user pick a file with the systems default file picker
/// For iOS iCloud drive needs to be configured
/// </summary>
/// <returns></returns>
public async Task<FileData> PickFile()
{
var media = await TakeMediaAsync();
return media;
}
private Task<FileData> TakeMediaAsync()
{
var id = GetRequestId();
var ntcs = new TaskCompletionSource<FileData>(id);
if (Interlocked.CompareExchange(ref _completionSource, ntcs, null) != null)
throw new InvalidOperationException("Only one operation can be active at a time");
var allowedUtis = new string[] {
UTType.UTF8PlainText,
UTType.PlainText,
UTType.RTF,
UTType.PNG,
UTType.Text,
UTType.PDF,
UTType.Image,
UTType.UTF16PlainText,
UTType.FileURL
};
var importMenu =
new UIDocumentMenuViewController(allowedUtis, UIDocumentPickerMode.Import)
{
Delegate = this,
ModalPresentationStyle = UIModalPresentationStyle.Popover
};
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(importMenu, true, null);
var presPopover = importMenu.PopoverPresentationController;
if (presPopover != null)
{
presPopover.SourceView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
presPopover.PermittedArrowDirections = UIPopoverArrowDirection.Down;
}
Handler = null;
Handler = (s, e) => {
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(new FileData(e.FilePath, e.FileName, () => { var url = new Foundation.NSUrl(e.FilePath); return new FileStream(url.Path, FileMode.Open, FileAccess.Read); }));
};
return _completionSource.Task;
}
public void WasCancelled(UIDocumentMenuViewController documentMenu)
{
var tcs = Interlocked.Exchange(ref _completionSource, null);
tcs?.SetResult(null);
}
private int GetRequestId()
{
var id = _requestId;
if (_requestId == int.MaxValue)
_requestId = 0;
else
_requestId++;
return id;
}
public async Task<bool> SaveFile(FileData fileToSave)
{
try
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToSave.FileName);
File.WriteAllBytes(fileName, fileToSave.DataArray);
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
public void OpenFile(NSUrl fileUrl)
{
var docControl = UIDocumentInteractionController.FromUrl(fileUrl);
var window = UIApplication.SharedApplication.KeyWindow;
var subViews = window.Subviews;
var lastView = subViews.Last();
var frame = lastView.Frame;
docControl.PresentOpenInMenu(frame, lastView, true);
}
public void OpenFile(string fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
}
public async void OpenFile(FileData fileToOpen)
{
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var fileName = Path.Combine(documents, fileToOpen.FileName);
if (NSFileManager.DefaultManager.FileExists(fileName))
{
var url = new NSUrl(fileName, true);
OpenFile(url);
}
else
{
await SaveFile(fileToOpen);
OpenFile(fileToOpen);
}
}
}
}
To answer my own question, i customized in plugin, like
Used DocumentPicker_DidPickDocumentAtUrls event instead of DocumentPicker_DidPickDocument.
while returning selected file used
new FileData(e.FilePath, e.FileName, () =>
{
var url = new Foundation.NSUrl(e.FilePath);
return new FileStream(url.Path, FileMode.Open, FileAccess.Read);
})
This solved my issue. Thanks.
There are several forks of the FilePicker Xamarin plugin. I recommend the following project, since it's the most actively maintained one:
https://github.com/jfversluis/FilePicker-Plugin-for-Xamarin-and-Windows (note: I'm one of the contributors to the project).
With this version of the plugin file picking should work. The example code from sandeep's answer was already incorporated into the latest version of the plugin. Be sure to read the README.md's Troubleshooting page in case you're getting problems.

How to find object type from URL SharePoint online (o365)?

I found out how to determine the object type from URL for SharePoint on prem:
https://blogs.msdn.microsoft.com/sanjaynarang/2009/04/06/find-sharepoint-object-type-from-url/
But I didn't find anything for SharePoint Online (CSOM).
Is it possible for SharePoint online?
For the most scenarios such as:
folder url, e.g. https://contoso.sharepoint.com//Documents/Forms/AllItems.aspx?RootFolder=%2FDocuments%2FArchive
list item url, e.g. https://contoso.sharepoint.com/Lists/ShoppingCart/DispForm.aspx?ID=9
list/library url, e.g. https://contoso.sharepoint.com/Lists/Announcements
page url, e.g. https://contoso.sharepoint.com/Lists/Announcements/Newsletter.aspx
the following example demonstrates how to determine client object type:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Web;
using Microsoft.SharePoint.Client;
namespace O365Console
{
static class ClientObjectExtensions
{
public static ClientObject ResolveClientObjectFromUrl(string resourceUrl, ICredentials credentials)
{
ClientObject targetObject = null;
var resourceUri = new Uri(resourceUrl);
using (var rootCtx = new ClientContext(resourceUri.Scheme + Uri.SchemeDelimiter + resourceUri.Host))
{
rootCtx.Credentials = credentials;
var webUrl = Web.WebUrlFromPageUrlDirect(rootCtx, resourceUri);
using (var ctx = new ClientContext(webUrl.ToString()))
{
ctx.Credentials = credentials;
var queryBag = System.Web.HttpUtility.ParseQueryString(resourceUri.Query);
if (queryBag["Id"] != null)
{
var listUrl = string.Join(string.Empty,
resourceUri.Segments.Take(resourceUri.Segments.Length - 1));
var list = ctx.Web.GetList(listUrl);
targetObject = TryRetrieve(() => list.GetItemById(Convert.ToInt32(queryBag["Id"])));
}
else if (queryBag["RootFolder"] != null)
{
var folderUrl = HttpUtility.UrlDecode(queryBag["RootFolder"]);
targetObject = TryRetrieve(() => ctx.Web.GetFolderByServerRelativeUrl(folderUrl));
}
else if (queryBag.Count > 0)
{
throw new Exception("Unsupported query string parameter found");
}
else
{
targetObject = TryRetrieve(() => ctx.Web.GetFileByServerRelativeUrl(resourceUri.AbsolutePath));
if (targetObject == null)
{
targetObject = TryRetrieve(() => ctx.Web.GetList(resourceUri.AbsolutePath),list => list.RootFolder);
if (targetObject == null || ((List)targetObject).RootFolder.ServerRelativeUrl != resourceUri.AbsolutePath)
targetObject = TryRetrieve(() => ctx.Web.GetFolderByServerRelativeUrl(resourceUri.AbsolutePath));
}
}
}
}
return targetObject;
}
private static T TryRetrieve<T>(Func<T> loadMethod, params Expression<Func<T,object>>[] retrievals) where T : ClientObject
{
try
{
var targetObject = loadMethod();
targetObject.Context.Load(targetObject, retrievals);
targetObject.Context.ExecuteQuery();
return targetObject;
}
catch
{
}
return default(T);
}
}
}
Usage
var credentials = GetCredentials(userName, password);
var clientObj = ClientObjectExtensions.ResolveClientObjectFromUrl("https://contoso.sharepoint.com/Lists/Announcements", credentials);
Console.WriteLine(clientObj.GetType().Name);
where
static ICredentials GetCredentials(string userName,string password)
{
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
return new SharePointOnlineCredentials(userName, securePassword);
}

PCLCrypto exception 'CryptographicException: Bad PKCS7 padding. Invalid length'

I'm struggling with the PCLCryptho libraby, I can't get it working without retrieving the exception 'CryptographicException: Bad PKCS7 padding. Invalid length'. Running the code once is working, but running it multiple times after each other fails (with different input strings). The decryption takes place after a new instance of the program. I'm running this code on iOS with Xamarin Forms. Here's my code (I'm using the same VI each time and save the salt in the Settinsg for now):
public static string EncryptAnswer(string answer, string passWord)
{
try
{
var keyMaterial = CreateKey(passWord);
var cipherTextBuffer = GetBytes(answer);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var encryptor = WinRTCrypto.CryptographicEngine.CreateEncryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (var bWriter = new BinaryWriter(cs))
{
bWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
cs.FlushFinalBlock();
}
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
return string.Empty;
}
}
public static string DecryptAnswer(string encryptedAnswer, string passWord)
{
try
{
var cipherTextBuffer = GetBytes(encryptedAnswer);
var keyMaterial = CreateKey(passWord);
var symmetricAlgorithm = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var symmetricKey = symmetricAlgorithm.CreateSymmetricKey(keyMaterial);
using (var decryptor = WinRTCrypto.CryptographicEngine.CreateDecryptor(symmetricKey, GetBytes("vivivivivivivivi")))
{
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
using (var binWriter = new BinaryWriter(cs))
{
binWriter.Write(cipherTextBuffer, 0, cipherTextBuffer.Length);
}
return GetString(ms.ToArray());
}
}
}
catch (Exception e)
{
}
return string.Empty;
}
public static byte[] CreateSalt()
{
var salt = WinRTCrypto.CryptographicBuffer.GenerateRandom(8);
CrossSettings.Current.AddOrUpdateValue("Salt", GetString(salt));
return salt;
}
private static byte[] GetSalt()
{
var saltString = CrossSettings.Current.GetValueOrDefault<string>("Salt");
var salt = GetBytes(saltString);
return salt;
}
private static byte[] CreateKey(string passWord)
{
var key = NetFxCrypto.DeriveBytes.GetBytes(passWord, GetSalt(), 1000, 32);
return key;
}
private static byte[] GetBytes(string str)
{
return Encoding.Unicode.GetBytes(str);
}
private static string GetString(byte[] bytes)
{
return Encoding.Unicode.GetString(bytes, 0, bytes.Length);
}
This seems to be equal to the answers and examples I found. Can someone tell me what's wrong?

Resources