XamarinForms FFImageLoading CachedImage issue - xamarin

I'm getting a .PNG image file from an API like so
public static async Task<CachedImage> GetImage(string UserID)
{
var URL = "assumeThisUrlPointsToServer"
HttpClient client = new HttpClient();
Stream stream = await client.GetStreamAsync(URL);
return new CachedImage { Source = ImageSource.FromStream(() => stream) };
}
and I am getting a file back and I am displaying it like so
<ffimageloading:CachedImage HeightRequest="52" Margin="13,0,16,0" Source="{Binding SourceOfReturnedCachedImage}"/>
Unfortunately, this is not working (blank). How do I get it to work?
Additional details : if I change it to an Image instead of CachedImage, then it works.
Now the funny thing is that if i specify a URI instead of downloading a file, like so,
return new CachedImage { Source = ImageSource.FromUri('http://www.website.com/image.png')};
Then it (CachedImage) works!

Stream is disposed after every image load, you must modify your code to:
public static async Task<CachedImage> GetImage(string UserID)
{
var URL = "assumeThisUrlPointsToServer"
HttpClient client = new HttpClient();
return new CachedImage { Source = ImageSource.FromStream(() => {
return await client.GetStreamAsync(URL);
})};
}

So xamarin provides a simple way to view images, you can just give the url of the image as the source of image/cachedimage so
<ffimageloading:CachedImage HeightRequest="52" Margin="13,0,16,0" Source="{Binding ImageURL}"/>
Where ImageURL is the URL I was downloading the image from

Related

Client-Side error when uploading image on server ASP.NET Core

I am struggling with uploading an image from thew client-side to a folder on the server-side in .Net Core.I used Postman to check if the method on the server-side is working and it does without any problem,but when I try to upload an image from the client-side,I get an error on the server-side of type NullReferenceException:Object reference not set to an instance of an object.This is the Post method on the server-side:
[HttpPost]
public async Task Post(IFormFile file)
{
if (string.IsNullOrWhiteSpace(_environment.WebRootPath))
{
_environment.WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
}
var uploads = Path.Combine(_environment.WebRootPath, "uploads");
//var fileName = file.FileName.Split('\\').LastOrDefault().Split('/').LastOrDefault();
if (!Directory.Exists(uploads)) Directory.CreateDirectory(uploads);
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
}
}
Apparently the method is thrown where I check if the length of the file is bigger than 0.On the client-side I get error "500 internal server error" and I tried to check using the debugger where exactly the error is thrown but i can't find anything that could resemble an error of some sort.This is the API method for the client-side:
public async Task UploadPictureAsync(MediaFile image)
{
User user = new User();
string pictureUrl = "http://10.0.2.2:5000/api/UploadPicture";
HttpContent fileStreamContent = new StreamContent(image.GetStream());
// user.Picture=GetImageStreamAsBytes(image.GetStream());
fileStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {FileName=Guid.NewGuid() + ".Png",Name="image"};
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
using (var client = new HttpClient(clientHandler))
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent);
var response = await client.PostAsync(pictureUrl, formData);
if(response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
}
}
The image is declared in the Model as byte array:
public byte[] Picture { get; set; }
Does someone understand why my POST method has this behavior since the server-side works perfectly but fails when I try to upload an image from the client-side?What I find weird though is that when i read the error and I look at the Content-Type it is "text/plain" instead of "form-data" and I have tried to set it at the MutipartFormDataContent like this:
formData.Headers.ContentType.MediaType = "multipart/form-data";
I also tried to set the MediaTypeHeaderValue on the client like this:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
I still get the wrong content type.
I have also tried a different approach with Stream instead of MediaFile but without any luck as it did not even hit the break point in debugger mode for the response.Any help would be appreciated! :)
I have managed to find the answer finalllyyyyy!!!The problem was on the client-side as I suspected and guess what,it was all about the correct name.It turns out that since on the server side I have IFormFile file I had to change the client side to take the parameter name "file" instead of image as well so that it could work.Thank you #Jason for the suggestions as I didn't understand the error from the first place and did some debugging on the server-side to help me figure it out.

How to show all images from a folder in Xamarin Cross-Platform app?

I am using VS 2017 to create a cross platform (UWP, Android, iOS) Xamarin app. I am trying to show all images from a folder on device as thumbnails (similar to gallery app, sample screenshot attached).
I have looked into WrapLayout sample code provided on Xamarin website (Link), but it's loading all images from internet using JSON
protected override async void OnAppearing()
{
base.OnAppearing();
var images = await GetImageListAsync();
foreach (var photo in images.Photos)
{
var image = new Image
{
Source = ImageSource.FromUri(new Uri(photo + string.Format("?width={0}&height={0}&mode=max", Device.OnPlatform(240, 240, 120))))
};
wrapLayout.Children.Add(image);
}
}
async Task<ImageList> GetImageListAsync()
{
var requestUri = "https://docs.xamarin.com/demo/stock.json";
using (var client = new HttpClient())
{
var result = await client.GetStringAsync(requestUri);
return JsonConvert.DeserializeObject<ImageList>(result);
}
}
I have also looked into Xamarin Media Plugin (Link), but it shows only one image at a time. Sample code -
await CrossMedia.Current.Initialize();
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
MainImage.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
But I am unable to find a way to implement these two (or any other methods) in such a way that I can create my own gallery section in my app.
You need to create an Activity in your specific platform. This activity will be launched as an intent throught your PCL project using, for instance, Dependency Services.
In this custom Activity you should have a GridView which fills its source from the current directory if the file fits your restrictions, such a specific extension, size, etc.
Finally, to get the selected image you just send the image path or whatever you need to the PCL project with DependencyService.

MediaPicker Not Working with Xamarin.Forms

I am new to xamarin.in my project open gallery for select image for this i have used IMediaPicker interface.my code as below:
IMediaPicker mediaPicker;
ImageSource imageSource;
async void OnTapEntertainer(object sender, EventArgs args)
{
await TakePicture();
}
private async Task TakePicture()
{
mediaPicker = DependencyService.Get<IMediaPicker>();
imageSource = null;
var mediaFile = await mediaPicker.SelectPhotoAsync(new CameraMediaStorageOptions
{
DefaultCamera = CameraDevice.Front,
MaxPixelDimension = 400
});
imageSource = ImageSource.FromStream(() => mediaFile.Source);
Imgmn.Source = imageSource;
}
I got mediaPicker is null value in this code.Please help me to solve this issue.
I have added capability required for perform function.
To use MediaPicker item from XLabs please double check you have comleted all the items below:
Add a reference to XLabs.IoC to all of your projects (PCL, Android, iOS, etc.)
Initialize Resolver using the following code snippet:
var resolverContainer = new SimpleContainer();
resolverContainer.Register<IMediaPicker, MediaPicker>()
.Register<IDependencyContainer>(t => resolverContainer);
Resolver.SetResolver(resolverContainer.GetResolver());
Put this code before Xamarin.Forms.Forms.Init method for each platform in your solution.
Use var mediaPicker = Resolver.Resolve<IMediaPicker>(); to get the instance.
As per the comments following process resolves the issue:
Add Dependency Service class in .Droid library project to resolve IMediaPicker as given in example and use [assembly:Xamarin.Forms.Dependency(typeof(MediaPicker))] Reference

Read both key values and files from multipart from data post request in ASP.NET WebAPI

I have an endpoint that needs to accept a file upload and also some other information from the client request. With the following code I can upload the file successfully but can't seem to figure out how to read the other info.
I make a test request from Postman with the following form data:
image -- myimage.jpg -- of type File
email -- a#b.com -- of type Text
The backend code looks like this:
[HttpPost]
public async Task<HttpResponseMessage> SharePhoto()
{
try
{
var provider = new MultipartMemoryStreamProvider();
var data = await Request.Content.ReadAsMultipartAsync(provider);
// this is how I get the image which I am succesfully passing to EmailService
var item = (StreamContent)provider.Contents[0];
using (var stream = new MemoryStream())
{
await item.CopyToAsync(stream);
String emailAddress;
EmailService.SendSharedPhoto(emailAddress, stream);
return Request.CreateResponse();
}
}
catch
{
// do stuff
}
}
In this example I am able to access provider.Contents[1] but can't seem to be able to get the value from it into emailAddress. I'm thinking it may be possible to use the same trick as the await item.CopyToASync(stream) from the image upload, but I'm hoping I can get a simpler solution to that. Any ideas?
I just barely answered a very similar question to this yesterday. See my answer here complete with sample controller code.
The method I ended up using is:
If the form elements are strings (and it worked for me since the mobiel frontend took responsability for input data) you can do this:
var streamContent = (StreamContent)provider.Contents[1];
var memStream = new MemoryStream();
await streamContent.CopyToAsync(memStream);
var actualString = Encoding.UTF8.GetString(x.ToArray());
If however the field needs to represent a collection of items, like for example the email list: ["a#b.com", "x#c.com"], etc a JavaScriptSerializer can be user, like so:
var streamContent = (StreamContent)provider.Contents[1];
var emailAddresses = await str.ReadAsStringAsync();
var jsSerializer = new JavaScriptSerializer();
var deserializedData = jsSerializer.Deserialize<string[]>(emailAddresses);
Note that this is nowhere near safe, though it is few lines of code and happens to work.

Download embedded images from google document

I'm trying to download embedded images in a google document using their Drive API and WebClient. A few of the images works just fine, and that is pure images. The others responds with a redirect to the login page instead of the file, so i suppose it has something to do with the credentials (I'm not setting any credetials to my WebClient right now). The images that fail looks like they are called drawings instead of images. Can that be the issue here?
The links that breaks looks like this:
https://docs.google.com/a/irissystem.se/drawings/image?id=HERE_IS_AN_UNIQUE_ID&rev=1&h=81&w=28&ac=1
Is there a way to download images like this using the HttpClient of DriveService-class or a way to apply my credentials from my DriveService to my WebClient instance?
The code below is used to parse the document and download the images.
foreach (HtmlNode img in doc.DocumentNode.SelectNodes("//img")) {
HtmlAttribute src = img.Attributes["src"];
using (WebClient webClient = new WebClient()) {
byte[] data = webClient.DownloadData(src.Value);
using (MemoryStream imagestream = new MemoryStream(data)) {
byte[] imagebinary = imagestream.ToArray();
Images.Add(src.Value, imagebinary);
}
}
}
UPDATE
Thanks to the comment below, i started thinking about the HttpClient and download stream and it turned out to be a good solution. The code below uses my Google DataService (authenticated and done) to download the embedded file as a stream. This works for both drawings and images, so it is a all round solution.
public byte[] GetFileByUrl(string Url, string ExportType = "text/plain") {
var stream = Service.HttpClient.GetStreamAsync(Url);
var result = stream.Result;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) {
result.CopyTo(ms);
return ms.ToArray();
}
}
The code for auth looks like this
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(SERVICE_ACCOUNT_EMAIL)
{
User = "xxx#xxx.com",
Scopes = new[] { DriveService.Scope.Drive }
}.FromCertificate(certificate));
Service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "xxx",
});

Resources