Xamarin.iOS Cannot display photo in Push Notification - xamarin.ios

I have a Notification Service Extension and an AppGroup. I save a photo from camera in the PCL project and copy it to the App Group Container (shared folder).
In the Notification Service Extension I try to download the photo from the App Group container and attach it to the notification but it just does not display in the notification.
I also cannot debug the Service Extension to see what is going. As far as I know that is not possible currently still in Xamarin unless someone can correct me on that please.
Here is the code:
1.in my PCL I save the photo to the AppGroup when a save button is pressed:
private void ButtonSavePhoto_Clicked(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(photoFilePath))
{
Preferences.Set(AppConstants.CUSTOM_PICTURE_FILE_PATH, photoFilePath);
Preferences.Set(AppConstants.CUSTOM_PHOTO_SET_KEY, true);
if (Device.RuntimePlatform == Device.iOS)
{
bool copiedSuccessfully = DependencyService.Get<IPhotoService>().CopiedFileToAppGroupContainer(photoFilePath);
if (copiedSuccessfully)
{
var customPhotoDestPath = DependencyService.Get<IPhotoService>().GetAppContainerCustomPhotoFilePath();
// save the path of the custom photo in the AppGroup container to pass to Notif Extension Service
DependencyService.Get<IGroupUserPrefs>().SetStringValueForKey("imageAbsoluteString", customPhotoDestPath);
// condition whether to use custom photo in push notification
DependencyService.Get<IGroupUserPrefs>().SetBoolValueForKey("isCustomPhotoSet", true);
}
}
buttonSavePhoto.IsEnabled = false;
}
}
2.in my iOS project, Dependency injection calls this method when pressing save button:
public bool CopiedFileToAppGroupContainer(string filePath)
{
bool success = false;
string suiteName = "group.com.company.appName";
var appGroupContainerUrl = NSFileManager.DefaultManager.GetContainerUrl(suiteName);
var appGroupContainerPath = appGroupContainerUrl.Path;
var directoryNameInAppGroupContainer = Path.Combine(appGroupContainerPath, "Pictures");
var filenameDestPath = Path.Combine(directoryNameInAppGroupContainer, AppConstants.CUSTOM_PHOTO_FILENAME);
try
{
Directory.CreateDirectory(directoryNameInAppGroupContainer);
if (File.Exists(filenameDestPath))
{
File.Delete(filenameDestPath);
}
File.Copy(filePath, filenameDestPath);
success = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return success;
}
Now the path for the photo in the App Group container is:
/private/var/mobile/Containers/Shared/AppGroup/12F209B9-05E9-470C-9C9F-AA959D940302/Pictures/customphoto.jpg
3.Finally in the Notification Service Extension I try to attach the photo to the push notification:
public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
{
ContentHandler = contentHandler;
BestAttemptContent = (UNMutableNotificationContent)request.Content.MutableCopy();
string imgPath;
NSUrl imgUrl;
string notificationBody = BestAttemptContent.Body;
string notifBodyInfo = "unknown";
string suiteName = "group.com.company.appname";
NSUserDefaults groupUserDefaults = new NSUserDefaults(suiteName, NSUserDefaultsType.SuiteName);
string pref1_value = groupUserDefaults.StringForKey("user_preference1");
string[] notificationBodySplitAtDelimiterArray = notificationBody.Split(',');
userPrefRegion = notificationBodySplitAtDelimiterArray[0];
bool isCustomAlertSet = groupUserDefaults.BoolForKey("isCustomAlert");
bool isCustomPhotoSet = groupUserDefaults.BoolForKey("isCustomPhotoSet");
string alarmPath = isCustomAlertSet == true ? "customalert.wav" : "default_alert.m4a";
if (isCustomPhotoSet)
{
// this is the App Group url of the custom photo saved in PCL
imgPath = groupUserDefaults.StringForKey("imageAbsoluteString");
}
else
{
imgPath = null;
}
if (imgPath != null )
{
imgUrl = NSUrl.FromString(imgPath);
}
else
{
imgUrl = null;
}
if (!string.IsNullOrEmpty(pref1_value))
{
if (BestAttemptContent.Body.Contains(pref1_value))
{
if (imgUrl != null)
{
// download the image from the AppGroup Container
var task = NSUrlSession.SharedSession.CreateDownloadTask(imgUrl, (tempFile, response, error) =>
{
if (error != null)
{
ContentHandler(BestAttemptContent);
return;
}
if (tempFile == null)
{
ContentHandler(BestAttemptContent);
return;
}
var cache = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User, true);
var cachesFolder = cache[0];
var guid = NSProcessInfo.ProcessInfo.GloballyUniqueString;
var fileName = guid + "customphoto.jpg";
var cacheFile = cachesFolder + fileName;
var attachmentUrl = NSUrl.CreateFileUrl(cacheFile, false, null);
NSError err = null;
NSFileManager.DefaultManager.Copy(tempFile, attachmentUrl, out err);
if (err != null)
{
ContentHandler(BestAttemptContent);
return;
}
UNNotificationAttachmentOptions options = null;
var attachment = UNNotificationAttachment.FromIdentifier("image", attachmentUrl, options, out err);
if (attachment != null)
{
BestAttemptContent.Attachments = new UNNotificationAttachment[] { attachment };
}
});
task.Resume();
}
BestAttemptContent.Title = "My Custom Title";
BestAttemptContent.Subtitle = "My Custom Subtitle";
BestAttemptContent.Body = "Notification Body";
BestAttemptContent.Sound = UNNotificationSound.GetSound(alarmPath);
}
}
else
{
pref1_value = "error getting extracting user pref";
}
// finally display customized notification
ContentHandler(BestAttemptContent);
}

/private/var/mobile/Containers/Shared/AppGroup/12F209B9-05E9-470C-9C9F-AA959D940302/Pictures/customphoto.jpg
From shared code, when image getting from AppGroup .You can check the file path whether work in this project.
imgPath = groupUserDefaults.StringForKey("imageAbsoluteString");
If not getting file from this path. You can get Url from AppGroup directly.Here is a sample as follow:
var FileManager = new NSFileManager();
var appGroupContainer = FileManager.GetContainerUrl("group.com.company.appName");
NSUrl fileURL = appGroupContainer.Append("customphoto.jpg", false);
And if fileURL can not be directly used, also can convert to NSData and save to local file system. This also can be a try.
Here is a sample below that grabs from local file system:
public static void Sendlocalnotification()
{
var localURL = "...";
NSUrl url = NSUrl.FromString(localURL) ;
var attachmentID = "image";
var options = new UNNotificationAttachmentOptions();
NSError error;
var attachment = UNNotificationAttachment.FromIdentifier(attachmentID, url, options,out error);
var content = new UNMutableNotificationContent();
content.Attachments = new UNNotificationAttachment[] { attachment };
content.Title = "Good Morning ~";
content.Subtitle = "Pull this notification ";
content.Body = "reply some message-BY Ann";
content.CategoryIdentifier = "message";
var trigger1 = UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false);
var requestID = "messageRequest";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger1);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
Console.Write("Notification Error");
}
});
}

Related

ASP.NET Core with AWS Lambda for processing EXCEL files

I created AWS Lambda ASP.NET Core 5 project using VS AWS Toolkit.
I am using default dockerfile that is created together with the project.
FROM public.ecr.aws/lambda/dotnet:5.0
WORKDIR /var/task
# This COPY command copies the .NET Lambda project's build artifacts from the host machine into the image.
# The source of the COPY should match where the .NET Lambda project publishes its build artifacts. If the Lambda function is being built
# with the AWS .NET Lambda Tooling, the `--docker-host-build-output-dir` switch controls where the .NET Lambda project
# will be built. The .NET Lambda project templates default to having `--docker-host-build-output-dir`
# set in the aws-lambda-tools-defaults.json file to "bin/Release/net5.0/linux-x64/publish".
#
# Alternatively Docker multi-stage build could be used to build the .NET Lambda project inside the image.
# For more information on this approach checkout the project's README.md file.
COPY "bin/Release/net5.0/linux-x64/publish" .
I created an endpoint that is used to upload excel file that should be parsed and some logic should be executed.
I tried few libs and the result is always the same: it is working on my local Win10 machine but it crashes when it is executed as AWS Lambda function.
Anyone has some idea what I should do with the dockerfile/AWS Lambda configuration to have to working in AWS Lambda?
https://github.com/ClosedXML/ClosedXML
Internal server error: System.IO.FileFormatException: File contains corrupted data.
at System.IO.Packaging.ZipPackage..ctor(Stream s, FileMode packageFileMode, FileAccess packageFileAccess)
at System.IO.Packaging.Package.Open(Stream stream, FileMode packageMode, FileAccess packageAccess)
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.OpenCore(Stream stream, Boolean readWriteMode)
at DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(Stream stream, Boolean isEditable, OpenSettings openSettings)
at DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(Stream stream, Boolean isEditable)
at ClosedXML.Excel.XLWorkbook.LoadSheets(Stream stream)
at ClosedXML.Excel.XLWorkbook.Load(Stream stream)
at ClosedXML.Excel.XLWorkbook..ctor(Stream stream, XLEventTracking eventTracking)
at ClosedXML.Excel.XLWorkbook..ctor(Stream stream)
at BasicAWSLambdaProject.Controllers.UploadController.UploadClosedXML() in D:\GitHub\kicaj29\aws-netcore-sample-system\BasicAWSLambdaProject\BasicAWSLambdaProject\Controllers\UploadController.cs:line 160
https://github.com/ExcelDataReader/ExcelDataReader
Internal server error: System.IO.InvalidDataException: Offset to Central Directory cannot be held in an Int64.
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen, Encoding entryNameEncoding)
at System.IO.Compression.ZipArchive..ctor(Stream stream)
at ExcelDataReader.Core.ZipWorker..ctor(Stream fileStream)
at ExcelDataReader.ExcelOpenXmlReader..ctor(Stream stream)
at ExcelDataReader.ExcelReaderFactory.CreateReader(Stream fileStream, ExcelReaderConfiguration configuration)
at BasicAWSLambdaProject.Controllers.UploadController.UploadExcelExcelDataReader() in D:\GitHub\kicaj29\aws-netcore-sample-system\BasicAWSLambdaProject\BasicAWSLambdaProject\Controllers\UploadController.cs:line 123
https://github.com/JanKallman/EPPlus
Internal server error: OfficeOpenXml.Packaging.Ionic.Zip.BadReadException: Could not read block - no data! (position 0x0001718A)
at OfficeOpenXml.Packaging.Ionic.Zip.SharedUtilities._ReadFourBytes(Stream s, String message)
at OfficeOpenXml.Packaging.Ionic.Zip.SharedUtilities.ReadInt(Stream s)
at OfficeOpenXml.Packaging.Ionic.Zip.ZipEntry.HandleUnexpectedDataDescriptor(ZipEntry entry)
at OfficeOpenXml.Packaging.Ionic.Zip.ZipEntry.ReadEntry(ZipContainer zc, Boolean first)
at Ionic.Zip.ZipInputStream.GetNextEntry()
at OfficeOpenXml.Packaging.ZipPackage..ctor(Stream stream)
at OfficeOpenXml.ExcelPackage.Load(Stream input, Stream output, String Password)
at OfficeOpenXml.ExcelPackage.Load(Stream input)
at OfficeOpenXml.ExcelPackage..ctor(Stream newStream)
at BasicAWSLambdaProject.Controllers.UploadController.UploadExcelEPPlus() in D:\GitHub\kicaj29\aws-netcore-sample-system\BasicAWSLambdaProject\BasicAWSLambdaProject\Controllers\UploadController.cs:line 90
https://github.com/nissl-lab/npoi
Internal server error: System.IO.IOException: ZIP entry size is too large
at NPOI.OpenXml4Net.Util.ZipInputStreamZipEntrySource.FakeZipEntry..ctor(ZipEntry entry, ZipInputStream inp)
at NPOI.OpenXml4Net.Util.ZipInputStreamZipEntrySource..ctor(ZipInputStream inp)
at NPOI.OpenXml4Net.OPC.ZipPackage..ctor(Stream in1, PackageAccess access)
at NPOI.OpenXml4Net.OPC.OPCPackage.Open(Stream in1)
at NPOI.Util.PackageHelper.Open(Stream is1)
at NPOI.XSSF.UserModel.XSSFWorkbook..ctor(Stream is1)
at BasicAWSLambdaProject.Controllers.UploadController.UploadExcelNPOI() in D:\GitHub\kicaj29\aws-netcore-sample-system\BasicAWSLambdaProject\BasicAWSLambdaProject\Controllers\UploadController.cs:line 59
And this is the Controller code (when it is run always only one method is uncommented and other are commented out)
[Route("api/[controller]")]
public class UploadController: Controller
{
[HttpPost]
public IActionResult UploadExcelNPOI()
{
try
{
var file = Request.Form.Files[0];
var receivedContent = "";
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
using (var s = file.OpenReadStream())
{
var xssWorkbook = new XSSFWorkbook(s);
var sheet = xssWorkbook.GetSheetAt(0);
var row = sheet.GetRow(0);
var cell = row.GetCell(0);
receivedContent = cell.StringCellValue;
}
return Ok(new { receivedContent });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex}");
}
}
[HttpPost]
public IActionResult UploadExcelEPPlus()
{
try
{
var file = Request.Form.Files[0];
var receivedContent = "";
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
using (var s = file.OpenReadStream())
{
using (ExcelPackage package = new ExcelPackage(s))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
receivedContent = worksheet.Cells[1, 1].Value.ToString();
}
}
return Ok(new { receivedContent });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex}");
}
}
[HttpPost]
public IActionResult UploadExcelExcelDataReader()
{
try
{
var file = Request.Form.Files[0];
var receivedContent = "";
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
using (var s = file.OpenReadStream())
{
using (var reader = ExcelReaderFactory.CreateReader(s))
{
do
{
while (reader.Read())
{
receivedContent = reader.GetString(0);
}
} while (reader.NextResult());
}
}
return Ok(new { receivedContent });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex}");
}
}
[HttpPost]
public IActionResult UploadClosedXML()
{
try
{
var file = Request.Form.Files[0];
var receivedContent = "";
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
using (var s = file.OpenReadStream())
{
using (var excel = new XLWorkbook(s))
{
var worksheet = excel.Worksheets.Worksheet(1);
receivedContent = worksheet.Cell(1, 1).Value.ToString();
}
}
return Ok(new { receivedContent });
}
else
{
return BadRequest();
}
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex}");
}
}
}
And the file is uploaded using Angular app - I am using exactly the same file in case when it is run locally on my Win10 and when it is hosted by AWS Lambda so because of this I think the file is ok. I can also open it in the excel.
I tried to use also IFormFile interface so instead od this
[HttpPost]
public IActionResult UploadExcelNPOI()
{
try
{
var file = Request.Form.Files[0];
var receivedContent = "";
if (file.Length > 0)
...
}
I do:
[HttpPost]
public IActionResult UploadExcelNPOI(IFormFile file)
{
try
{
var receivedContent = "";
if (file.Length > 0)
...
}
but I still crashes when it is run as lambda.
This is angular code for uploading the file:
public uploadFile = (files) => {
if (files.length === 0) {
return;
}
let fileToUpload = <File>files[0];
const formData = new FormData();
formData.append('file', fileToUpload, fileToUpload.name);
this.httpClient.post(`${environment.apiUrl}api/upload`, formData, {reportProgress: true, observe: 'events'})
.subscribe(event => {
if (event.type === HttpEventType.UploadProgress)
this.UploadProgress = Math.round(100 * event.loaded / event.total);
else if (event.type === HttpEventType.Response) {
this.UploadMessage = 'Upload success.';
}
});
}
-Jacek

Uplaoded Image but with 0 KB size

I'm using .NET Core 3.1 but I encountered a weird problem!
the problem is any uploaded image the size of it is 0KB
when I restart the IIS and trying again will upload it without any problem but after that, the problem returns back.
I tried this solution by making my code async but with no luck
I changed my system file to be accessible by my Application pool user but with no luck
Here is my code :
public Document shareWithUsers([FromForm] CreateDocumentDto documentDto)
{
List<CreateUserType1DocumentsDto> listOfCreateUserType1Documents = new List<CreateUserType1DocumentsDto>();
List<CreateHDDocumentsDto> listOfCreateHDDocuments = new List<CreateHDDocumentsDto>();
if (documentDto.listOfUserType1Documents != null)
{
foreach (var item in documentDto.listOfUserType1Documents)
{
listOfCreateUserType1Documents.Add(JsonConvert.DeserializeObject<CreateUserType1DocumentsDto>(item));
}
}
else if (documentDto.listOfHDDocuments != null)
{
foreach (var item in documentDto.listOfHDDocuments)
{
listOfCreateHDDocuments.Add(JsonConvert.DeserializeObject<CreateHDDocumentsDto>(item));
}
}
if (documentDto.sharedText == null)
{
if (documentDto.document != null) //that mean user upload file
{
if (documentDto.document.Length > 0)
{
var UploadedFilesPath = Path.Combine(hosting.WebRootPath/*wwwroot path*/, "UploadedFiles" /*folder name in wwwroot path*/);
var filePath = Path.Combine(UploadedFilesPath, documentDto.document.FileName);
//documentDto.docUrl = filePath;
var documentObject = new Document();
using (var stream = new FileStream(filePath, FileMode.Create))
{
documentDto.document.CopyToAsync(stream);// Use stream
}
if (documentDto.listOfUserType1Documents != null)
{
documentObject.listOfUserType1Documents = ObjectMapper.Map<List<UserType1Documents>>(listOfCreateUserType1Documents);
}
else if (documentDto.listOfHDDocuments != null)
{
documentObject.listOfHDDocuments = ObjectMapper.Map<List<HDDocuments>>(listOfCreateHDDocuments);
}
documentObject.docTtitle = documentDto.docTtitle;
documentObject.docName = documentDto.docName;
documentObject.docUrl = filePath;
return _repository.Insert(documentObject);
}
}
}
else
{ //that mean user upload text
var documentObject = new Document();
if (documentDto.listOfUserType1Documents != null)
{
documentObject.listOfUserType1Documents = ObjectMapper.Map<List<UserType1Documents>>(listOfCreateUserType1Documents);
}
else if (documentDto.listOfHDDocuments != null)
{
documentObject.listOfHDDocuments = ObjectMapper.Map<List<HDDocuments>>(listOfCreateHDDocuments);
}
documentObject.sharedText = documentDto.sharedText;
return _repository.Insert(documentObject);
}
return null;
}
My code works only if I change both of them (CopyTo and Insert ) to Async with await
await CopyToAsync()
await InsertAsync()

Need help to deal with Photo for Xamarin forms

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.

How to save Rotativa PDF on server

I am using Rotativa to generate PDF in my "MVC" application. How can I save Rotativa PDF? I need to save the document on a server after all the process is completed.
Code below:
public ActionResult PRVRequestPdf(string refnum,string emid)
{
var prv = functions.getprvrequest(refnum, emid);
return View(prv);
}
public ActionResult PDFPRVRequest()
{
var prv = Session["PRV"] as PRVRequestModel;
byte[] pdfByteArray = Rotativa.WkhtmltopdfDriver.ConvertHtml("Rotativa", "Approver", "PRVRequestPdf");
return new Rotativa.ViewAsPdf("PRVRequestPdf", new { refnum = prv.rheader.request.Referenceno });
}
You can give this a try
var actionResult = new ActionAsPdf("PRVRequestPdf", new { refnum = prv.rheader.request.Referenceno, emid = "Whatever this is" });
var byteArray = actionResult.BuildPdf(ControllerContext);
var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
fileStream.Write(byteArray, 0, byteArray.Length);
fileStream.Close();
If that doesn't do the trick then, you can follow the answers here
Just make sure if you do it this way not to have PRVRequestPdf return as a PDF View, rather a normal View like you have above (only mention as managed to fall foul of that myself causing lots of fun).
Another useful answer:
I found the solution here
var actionPDF = new Rotativa.ActionAsPdf("YOUR_ACTION_Method", new { id = ID, lang = strLang } //some route values)
{
//FileName = "TestView.pdf",
PageSize = Size.A4,
PageOrientation = Rotativa.Options.Orientation.Landscape,
PageMargins = { Left = 1, Right = 1 }
};
byte[] applicationPDFData = actionPDF.BuildPdf(ControllerContext);
This is the original thread
You can achieve this with ViewAsPdf.
[HttpGet]
public ActionResult SaveAsPdf(string refnum, string emid)
{
try
{
var prv = functions.getprvrequest(refnum, emid);
ViewAsPdf pdf = new Rotativa.ViewAsPdf("PRVRequestPdf", prv)
{
FileName = "Test.pdf",
CustomSwitches = "--page-offset 0 --footer-center [page] --footer-font-size 8"
};
byte[] pdfData = pdf.BuildFile(ControllerContext);
string fullPath = #"\\server\network\path\pdfs\" + pdf.FileName;
using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write))
{
fileStream.Write(pdfData, 0, pdfData.Length);
}
return Json(new { isSuccessful = true }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
//TODO: ADD LOGGING
return Json(new { isSuccessful = false, error = "Uh oh!" }, JsonRequestBehavior.AllowGet);
//throw;
}
}
You can simply try this:
var fileName = string.Format("my_file_{0}.pdf", id);
var path = Server.MapPath("~/App_Data/" + fileName);
System.IO.File.WriteAllBytes(path, pdfByteArray );

How do I programmatically create a FTP site in IIS7 on Windows7?

I am looking to do this step: 'Creating a New FTP Site by Editing the IIS 7.0 Configuration Files' with a batch file and was wondering if anybody has done this already?
http://learn.iis.net/page.aspx/301/creating-a-new-ftp-site/
Try this. You need to reference the COM component "AppHostAdminLibrary"
using AppHostAdminLibrary;
...
public void AddFtp7Site(String siteName, String siteId, String siteRoot) {
String configPath;
String configSectionName;
var fNewSite = false;
var fNewApplication = false;
var fNewVDir = false;
//
// First setup the sites section
//
configPath = "MACHINE/WEBROOT/APPHOST";
configSectionName = "system.applicationHost/sites";
var adminManager = new AppHostAdminLibrary.AppHostWritableAdminManager();
adminManager.CommitPath = configPath;
try {
var sitesElement = adminManager.GetAdminSection(configSectionName, configPath);
IAppHostElement newSiteElement = null;
//
// check if site already exists
//
for (var i = 0; i < sitesElement.Collection.Count; i++) {
var siteElement = sitesElement.Collection[i];
if (siteElement.Properties["name"].Value.Equals(siteName) &&
siteElement.Properties["id"].Value.Equals(siteId)) {
newSiteElement = siteElement;
break;
}
}
if (newSiteElement == null) {
//
// Site doesn't exist yet. Add new site node
//
newSiteElement = sitesElement.Collection.CreateNewElement("");
newSiteElement.Properties["id"].Value = siteId;
newSiteElement.Properties["name"].Value = siteName;
fNewSite = true;
}
// setup bindings for the new site
var ftpBindingString = "*:21:";
var Bindings = newSiteElement.GetElementByName("bindings");
var BindingElement = Bindings.Collection.CreateNewElement("");
BindingElement.Properties["protocol"].Value = "ftp";
BindingElement.Properties["bindingInformation"].Value = ftpBindingString;
try {
Bindings.Collection.AddElement(BindingElement, 0);
}
catch (Exception ex) {
if (ex.Message != "") // ERROR_ALREADY_EXISTS ?
{
throw;
}
}
IAppHostElement newApplication = null;
//
// check if root application already exists
//
for (var i = 0; i < newSiteElement.Collection.Count; i++) {
var applicationElement = newSiteElement.Collection[i];
if (applicationElement.Properties["path"].Value.Equals("/")) {
newApplication = applicationElement;
break;
}
}
if (newApplication == null) {
newApplication = newSiteElement.Collection.CreateNewElement("application");
newApplication.Properties["path"].Value = "/";
fNewApplication = true;
}
IAppHostElement newVirtualDirectory = null;
//
// search for the root vdir
//
for (var i = 0; i < newApplication.Collection.Count; i++) {
var vdirElement = newApplication.Collection[i];
if (vdirElement.Properties["path"].Value.Equals("/")) {
newVirtualDirectory = vdirElement;
break;
}
}
if (newVirtualDirectory == null) {
newVirtualDirectory = newApplication.Collection.CreateNewElement("");
newVirtualDirectory.Properties["path"].Value = "/";
fNewVDir = true;
}
newVirtualDirectory.Properties["physicalPath"].Value = siteRoot;
if (fNewVDir) {
newApplication.Collection.AddElement(newVirtualDirectory, 0);
}
if (fNewApplication) {
newSiteElement.Collection.AddElement(newApplication, 0);
}
var ftpSiteSettings = newSiteElement.GetElementByName("ftpServer").GetElementByName("security").GetElementByName("authentication");
Console.WriteLine("Enable anonymous authentication");
var anonAuthSettings = ftpSiteSettings.GetElementByName("anonymousAuthentication");
anonAuthSettings.Properties["enabled"].Value = "true";
Console.WriteLine("Disable basic authentication");
var basicAuthSettings = ftpSiteSettings.GetElementByName("basicAuthentication");
basicAuthSettings.Properties["enabled"].Value = "false";
BindingElement.Properties["bindingInformation"].Value = "*:21:";
//
// Time to add new site element and commit changes
//
if (fNewSite) {
sitesElement.Collection.AddElement(newSiteElement, 0);
}
adminManager.CommitChanges();
}
catch (Exception ex) {
Console.WriteLine("Error occured in AddDefaultFtpSite: " + ex.Message);
}
//
// Add <authorization> section to allow everyone Read
//
Console.WriteLine("Enable everyone Read access");
try {
configPath = "MACHINE/WEBROOT/APPHOST/" + siteName;
configSectionName = "system.ftpServer/security/authorization";
var azSection = adminManager.GetAdminSection(configSectionName, configPath);
azSection.Collection.Clear();
var newAzElement = azSection.Collection.CreateNewElement("");
newAzElement.Properties["accessType"].Value = "Allow";
newAzElement.Properties["users"].Value = "*";
newAzElement.Properties["permissions"].Value = "Read";
azSection.Collection.AddElement(newAzElement, 0);
adminManager.CommitChanges();
}
catch (Exception ex) {
Console.WriteLine("Error occured while adding authorization section: " + ex.Message);
}
}
Does this help?:
http://blogs.iis.net/jaroslad/archive/2007/06/13/how-to-programatically-create-an-ftp7-site.aspx

Resources