I am making a Native IOS app using C#. I have a registration form and i am sending form data with image. but i am unable to send image as my UIImage control does not contains its path or name.I am sending Form to web api in multipart . text field data is uploading but image is not being upoloaded .
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
Here's how you can pick image from Camera/Gallery onto an UIImageView
, and then upload;
Use UIImagePickerController for selecting image from Gallery/Camera
UIImagePickerController galleryImagePicker;
UIImagePickerController cameraImagePicker;
Use the below function on clicking a button or on your ImageView to bring a pop for to select between Camera/Gallery:
void ShowSelectPicPopup ()
{
var actionSheetAlert = UIAlertController.Create ("Select picture",
"Complete action using", UIAlertControllerStyle.ActionSheet);
actionSheetAlert.AddAction (UIAlertAction.Create ("Camera",
UIAlertActionStyle.Default, (action) => HandleCameraButtonClick ()));
actionSheetAlert.AddAction (UIAlertAction.Create ("Gallery",
UIAlertActionStyle.Default, (action) => HandleGalleryButtonClick ()));
actionSheetAlert.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Cancel,
(action) => Console.WriteLine ("Cancel button pressed.")));
// Required for iPad - You must specify a source for the Action Sheet since it is
// displayed as a popover
var presentationPopover = actionSheetAlert.PopoverPresentationController;
if (presentationPopover != null) {
presentationPopover.SourceView = View;
presentationPopover.PermittedArrowDirections = UIPopoverArrowDirection.Up;
}
PresentViewController (actionSheetAlert, true, null);
}
Now the actions:
void HandleGalleryButtonClick ()
{
if (galleryImagePicker == null) {
galleryImagePicker = new UIImagePickerController ();
galleryImagePicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
galleryImagePicker.MediaTypes = UIImagePickerController.AvailableMediaTypes (UIImagePickerControllerSourceType.PhotoLibrary);
galleryImagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
galleryImagePicker.Canceled += Handle_Canceled;
}
PresentViewController (galleryImagePicker, true, () => { });
}
void HandleCameraButtonClick ()
{
if (cameraImagePicker == null) {
cameraImagePicker = new UIImagePickerController ();
cameraImagePicker.PrefersStatusBarHidden ();
cameraImagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
cameraImagePicker.FinishedPickingMedia += Handle_FinishedPickingCameraMedia;
cameraImagePicker.Canceled += Handle_CameraCanceled;
}
PresentViewController (cameraImagePicker, true, () => { });
}
void Handle_Canceled (object sender, EventArgs e)
{
galleryImagePicker.DismissViewController (true, () => { });
}
protected void Handle_FinishedPickingMedia (object sender, UIImagePickerMediaPickedEventArgs e)
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info [UIImagePickerController.MediaType].ToString ()) {
case "public.image":
Console.WriteLine ("Image selected");
isImage = true;
break;
case "public.video":
Console.WriteLine ("Video selected");
break;
}
// get common info (shared between images and video)
var referenceURL = e.Info [new NSString ("UIImagePickerControllerReferenceUrl")] as NSUrl;
if (referenceURL != null)
Console.WriteLine ("Url:" + referenceURL);
// if it was an image, get the other image info
if (isImage) {
// get the original image
var originalImage = e.Info [UIImagePickerController.OriginalImage] as UIImage;
if (originalImage != null) {
// do something with the image
Console.WriteLine ("got the original image");
Picture.Image = originalImage; // Picture is the ImageView
picAssigned = true;
}
} else { // if it's a video
// get video url
var mediaURL = e.Info [UIImagePickerController.MediaURL] as NSUrl;
if (mediaURL != null) {
Console.WriteLine (mediaURL);
}
}
// dismiss the picker
galleryImagePicker.DismissViewController (true, () => { });
}
protected void Handle_FinishedPickingCameraMedia (object sender, UIImagePickerMediaPickedEventArgs e)
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info [UIImagePickerController.MediaType].ToString ()) {
case "public.image":
Console.WriteLine ("Image selected");
isImage = true;
break;
case "public.video":
Console.WriteLine ("Video selected");
break;
}
// get common info (shared between images and video)
var referenceURL = e.Info [new NSString ("UIImagePickerControllerReferenceUrl")] as NSUrl;
if (referenceURL != null)
Console.WriteLine ("Url:" + referenceURL);
// if it was an image, get the other image info
if (isImage) {
// get the original image
var originalImage = UIHelper.RotateCameraImageToProperOrientation (e.Info [UIImagePickerController.OriginalImage] as UIImage, 320);
if (originalImage != null) {
// do something with the image
Console.WriteLine ("got the original image");
Picture.Image = originalImage; // display
picAssigned = true;
}
} else { // if it's a video
// get video url
var mediaURL = e.Info [UIImagePickerController.MediaURL] as NSUrl;
if (mediaURL != null) {
Console.WriteLine (mediaURL);
}
}
// dismiss the picker
cameraImagePicker.DismissViewController (true, () => { });
}
void Handle_CameraCanceled (object sender, EventArgs e)
{
cameraImagePicker.DismissViewController (true, () => { });
}
You may need to add following two permissions in your Info.plist to access Camera/Gallery
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
They're both String, and Value can be something like "YourAppName needs access to use your camera"
And finally to upload image as multipart:
First convert the image to byte array
public static byte[] ConvertImageToByteArray(UIImage Picture) {
byte [] image = null;
try {
using (NSData imageData = Picture.Image.AsJPEG (0.5f)) { // Here you can set compression %, 0 = no compression, 1 = max compression, or the other way around, I'm not sure
image = new byte [imageData.Length];
Marshal.Copy (imageData.Bytes, image, 0, Convert.ToInt32 (imageData.Length));
} catch (Exception e) {
Console.WriteLine ("Error @ Picture Byte Conversion: " + e.Message);
}
return image;
}
And finally to post the image, I use modernhttpclient
public async Task PostPicture (byte [] image)
{
try {
string url = .....;
var requestContent = new MultipartFormDataContent ();
ByteArrayContent content = content = new ByteArrayContent (image);
content.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (content, "file", "post" + DateTime.Now + ".jpg"); // change file name as per your requirements
string result = await HttpCall.PostMultiPartContent (url, requestContent, null);
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (ex.Message);
}
}
public class HttpCall
{
public static async Task<string> PostMultiPartContent (string url, MultipartFormDataContent content, Action<int> progressAction) // Here you can pass an handler to keep track of the upload % in your UI, I'm passing null above. (Not keeping track)
{
try {
var request = new HttpRequestMessage (HttpMethod.Post, url);
var progressContent = new ProgressableStreamContent (content, 4096, (sent, total) => {
var percentCompletion = (int)(((double)sent / total) * 100);
System.Diagnostics.Debug.WriteLine ("Completion: " + percentCompletion);
if (progressAction != null)
progressAction (percentCompletion);
});
request.Content = progressContent;
var client = new HttpClient();
var response = await client.SendAsync (request);
string result = await response.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
}