Decompress stream from HttpClient using SharpZipLib in Xamarin.Forms - xamarin.forms

I am trying decompress stream from HttpClient using SharpZipLib in Xamarin.Forms. This code perfectly works on iOS, but on Android CanDecompressEntry() always returns false. What i'm missing? Maybe Android need some permissions?
var zipStream = await httpClient.GetStreamAsync(url);
using (ZipInputStream s = new ZipInputStream(zipStream))
{
ZipEntry theEntry;
//const int size = 2048;
byte[] data = new byte[2048];
Debug.WriteLine(s.CanDecompressEntry);
while ((theEntry = s.GetNextEntry()) != null)
{
if (theEntry.IsFile)
{
string str = "";
while (true)
{
int size = s.Read(data, 0, data.Length);
if (size > 0)
{
str += new UTF8Encoding().GetString(data, 0, size);
}
else
{
files.Add(theEntry.Name.Substring(0,theEntry.Name.Length-5), str);
break;
}
}
}
}
}
return files;

Ok. I just set ConfigureAwait to false, and it works.
var zipStream = await httpClient.GetStreamAsync(url).ConfigureAwait(false);

Related

How to pass value from Controller to View (Just In Time/Async)

My Controller/Method has While loop with progress of reading going on and at each step I want to show that progress in View.
I'm calling function with While loop in different Thread but once return state happens
I'm getting error: 'Cannot access a closed file.' - because file closes after return.
public async Task<JsonResult> Convert()
{
int progress = 0;
new Thread(delegate () {
byte[] stream = html.ReadAsBytesAndOutPercent(out progress);
}).Start();
if (progress != 100)
{
return Json(progress);
} else {
...
}
}
public static byte[] ReadAsBytesAndOutPercent(this IFormFile file, out int progress)
{
long totalBytesOfFile = file.Length;
byte[] byteToRet = new byte[totalBytesOfFile];
byte[] buffer = new byte[16 * 1024];
int totalReadBytes = 0;
int readBytes;
progress = 0;
using (var ms = new MemoryStream())
{
var reader = file.OpenReadStream();
while ((readBytes = reader.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, readBytes);
totalReadBytes += readBytes;
progress = (int)((float)totalReadBytes / (float)totalBytesOfFile * 100);
}
return ms.ToArray();
}
}
On JS side I'm planing to call Controller with Interval every 10 millseconds
setInterval(function () {
$.post(
"/Home/Convert",
function (progress) {
$("#bar").css({ width: progress + "%" });
$("#label").html(progress + "%");
}
);
},
10
);
How to achive something like that ? I'm lacking knowledge at this point any article to clear thing up would be appriciated.
If you are using ASP.NET 6 then you can use AsyncEnumerable. Please go through this blog -
https://asp.net-hacker.rocks/2021/09/02/aspnetcore6-async-stream.html

Passing images from one page to another in Xamarin Forms

In my app I need to pass images from one page to another page image view to display. I am taking a photo from camera and do some stuffs, then I want to send that images to the second page.
if (await isCamAvailable())
{
MediaFile photo1 = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions() { Directory = "NewBusiness", Name = "image1.jpg", PhotoSize = PhotoSize.MaxWidthHeight, MaxWidthHeight = 1024, CompressionQuality = 95 });
if (photo1 != null)
{
PhotoImage1.Source = ImageSource.FromStream(() => { return photo1.GetStream(); });
countList.Remove("a");
countList.Add("a");
}
}
Then I am added it to a string array by doing
private List<string> sendImgList = new List<string>();
sendImgList.Add(createImgByteString(photo1.GetStream()));
private string createImgByteString(Stream data)
{
var bytes = new byte[data.Length];
return Convert.ToBase64String(bytes);
}
Then from second page (for testing i just added only one image)
foreach (string ss in imgList) {
byte[] Base64Stream = Convert.FromBase64String(ss);
imgView.Source = ImageSource.FromStream(() => new MemoryStream(Base64Stream));
}
I followed this example. But image not showing.
https://forums.xamarin.com/discussion/139360/how-to-transfer-images-from-one-page-to-another
Also getting this in logcat..
[0:] ImageLoaderSourceHandler: Image data was invalid: Xamarin.Forms.StreamImageSource05-29 14:22:43.758 W/monodroid-assembly( 8737): typemap: unable to find mapping to a Java type from managed type 'System.Byte, mscorlib'
It seems that you used the Media.Plugin . Why don't you pass the ImageSource directly?
If you do want to convert it to byte array , check the following code
public byte[] GetImageStreamAsBytes(Stream input)
{
var buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
var imgDate = GetImageStreamAsBytes(photo1.GetStream());
It would be better to pass the byte array directly .
The best mode to pass parameter in pages is with Prism.
https://prismlibrary.com/docs/xamarin-forms/navigation/passing-parameters.html
>
_navigationService.NavigateAsync(new Uri("MainPage", new NavigationParameters
{
{ "key_parameter", image }
})));
And on other page:
>
public override void OnNavigatedTo(INavigationParameters parameters)
{
image = (Image)parameters["key_parameter"];
}

Uploading large pictures to FTP freezes the app

I am trying to upload some pictures to my FTP in a form. It´s working great on my Huawei P20, but it has been reported to me that on a phone with less RAM the app freezes when they are trying to upload larger pictures.
After the picture selection (max of 4) I resize the images and compress them to reduce the size, but with no luck
Code:
public static byte[] RotateImage(string path)
{
byte[] imageBytes;
var originalImage = BitmapFactory.DecodeFile(path);
var rotation = GetRotation(path);
//Width 3000 Height 4000
var width = (originalImage.Width * 0.25);
var height = (originalImage.Height * 0.25);
if(originalImage.Height>2400)
{
width = (originalImage.Width * 0.20);
height = (originalImage.Height * 0.20);
}
if (originalImage.Height < 600)
{
width = (originalImage.Width * 0.80);
height = (originalImage.Height * 0.80);
}
var scaledImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, true);
Bitmap rotatedImage = scaledImage;
if (rotation != 0)
{
var matrix = new Matrix();
matrix.PostRotate(rotation);
rotatedImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
scaledImage.Recycle();
scaledImage.Dispose();
}
using (var ms = new MemoryStream())
{
if (rotatedImage.Width > 1000 || rotatedImage.Height > 1000)
{
rotatedImage.Compress(Bitmap.CompressFormat.Jpeg, 30, ms);
}
if (rotatedImage.Width < 500 || rotatedImage.Height < 500)
{
rotatedImage.Compress(Bitmap.CompressFormat.Jpeg, 60, ms);
}
if (rotatedImage.Width <= 1000 && rotatedImage.Width >= 500)
{
rotatedImage.Compress(Bitmap.CompressFormat.Jpeg, 45, ms);
}
imageBytes = ms.ToArray();
}
originalImage.Recycle();
rotatedImage.Recycle();
originalImage.Dispose();
rotatedImage.Dispose();
GC.Collect();
return imageBytes;
}
Then I send them to the MessagingCenter and retrieve them in PCL.
The application freezes when I try to upload it to FTP
Code in PCL:
for (int i = 0; i < _images.Count; i++)
{
DependencyService.Get<IFtpWebRequest>().upload("FTP", _images[i], "SITE", "PASSWORD", "DIRECTORY");
}
and the platform specific code I am calling is:
public string upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
{
try
{
WebRequest request = WebRequest.Create(FtpUrl+UploadDirectory);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Credentials = new NetworkCredential(userName, password);
using (var resp = (FtpWebResponse)request.GetResponse())
{
}
}
catch(Exception e) { }
try
{
string PureFileName = new FileInfo(fileName).Name;
String uploadUrl = String.Format("{0}{1}/{2}", FtpUrl, UploadDirectory, PureFileName);
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
req.Proxy = null;
req.Method = WebRequestMethods.Ftp.UploadFile;
req.Credentials = new NetworkCredential(userName, password);
req.UseBinary = true;
req.UsePassive = true;
byte[] data = File.ReadAllBytes(fileName);
req.ContentLength = data.Length;
Stream stream = req.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
FtpWebResponse res = (FtpWebResponse)req.GetResponse();
return res.StatusDescription;
}
catch (Exception err)
{
return err.ToString();
}
}
The expected result should be the app not freezing on any phone.
What could I do to prevent it?
Further increasing compression isnt best solution either as some phones upload it no problem and therefore I could achieve higher quality.
EDIT: When uploading a large picture to FTP and I check the pic on FTP its like 1/10 of the picture is uploaded, rest is blank
EDIT2: Moving the function to a different thread does not freeze the application anymore but still only part of the iamge is uploaded on devices with less memory, how do I somehow force the whole image to be uploaded?
When uploading a large picture to FTP and I check the pic on FTP its like 1/10 of the picture is uploaded, rest is blank
If the uploaded image is very large, then this will be a time-consuming operation. If it is placed in the main UI thread, it will consume a lot of memory and time. When the memory of the mobile phone is large, it may be able to do the task, but when When the phone is not big, then the problem will arise.
You need to move upload method to a backgroud thread, then it will not affect UI thread.
If in Android , Have a try with Task :
public async Task<string> upload(string FtpUrl, string fileName, string userName, string password, string UploadDirectory = "")
{
await Task.Run(() =>
{
try
{
WebRequest request = WebRequest.Create(FtpUrl+UploadDirectory);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Credentials = new NetworkCredential(userName, password);
using (var resp = (FtpWebResponse)request.GetResponse())
{
}
}
catch(Exception e) { }
...
});
}

Download file with progress bar in Xamarin Forms

I am trying to make a download page in Xamarin Forms (PCL, so WebClient is not usable) with a Download progress bar. I have used the following information from Xamarin, but without success:
http://developer.xamarin.com/recipes/ios/network/web_requests/download_a_file/
http://developer.xamarin.com/recipes/cross-platform/networking/download_progress/
This is my current code (with a working progress bar):
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using System.Net.Http;
using System.IO;
using System.Threading.Tasks;
namespace DownloadExample
{
public partial class DownloadPage : ContentPage
{
public DownloadPage ()
{
InitializeComponent ();
DownloadFile("https://upload.wikimedia.org/wikipedia/commons/3/3d/LARGE_elevation.jpg");
}
private async Task<long> DownloadFile(string url)
{
long receivedBytes = 0;
long totalBytes = 0;
HttpClient client = new HttpClient ();
using (var stream = await client.GetStreamAsync(url)) {
byte[] buffer = new byte[4096];
totalBytes = stream.Length;
for (;;) {
int bytesRead = await stream.ReadAsync (buffer, 0, buffer.Length);
if (bytesRead == 0) {
await Task.Yield ();
break;
}
receivedBytes += bytesRead;
int received = unchecked((int)receivedBytes);
int total = unchecked((int)totalBytes);
double percentage = ((float) received) / total;
progressBar1.Progress = percentage;
}
}
return receivedBytes;
}
}
}
Now, I need to save the file to my local storage. But, in this example, I'm not getting the file content, so I can't write it to my local storage. What do I need to change in the code to make this possible?
FYI: In this example, I'm downloading an image, but it will be a .pdf / .doc / .docx in feature.
Thanks in advance.
BR, FG
Think your article,I also solved download file
WebClient client = new WebClient();
using (var stream = await client.OpenReadTaskAsync(Download point))
{
using (MemoryStream ms = new MemoryStream())
{
var buffer = new byte[BufferSize];
int read = 0;
totalBytes = Int32.Parse(client.ResponseHeaders[HttpResponseHeader.ContentLength]);
while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);//important : receive every buffer
receivedBytes += read;
received = unchecked((int)receivedBytes);
total = unchecked((int)totalBytes);
percentage = ((float)received) / total;
progressBar1.Progress = percentage;
labProg.Text = AppResources.MsgDownloadprogress + Math.Truncate(percentage * 100).ToString() + "%";
}//END while
Stream ALLstream = new MemoryStream(ms.ToArray());//important change Stream
App.APK.GenApkFile(ALLstream);//change APK file and save memory of phone
}//END using (MemoryStream
stream.Close();
}//END using (var stream
You actually copy the file content to your buffer inside the for loop. Concat the buffer content each run of that loop into a new byte[] fileContentBuffer and you have access to the contents which you can save in the local storage.

SMPP message length error using jamaa more than 160 characters

I am using jamaa-smpp to send sms. But I am not able to send more than 160 characters using the api. I am using the following link http://jamaasmpp.codeplex.com/
The code is as follows
SmppConnectionProperties properties = _client.Properties;
properties.SystemID = "test";
properties.Password = "test1";
properties.Port = 101; //IP port to use
properties.Host = "..."; //SMSC host name or IP Address
....
Is it possible to send more than 160 character using that API.
I found the solution it was there on the website discussion. I am posting it here so that one can find solution here.
I replaced the existing function in the TextMessage.cs (JamaaTech.Smpp.Net.Client).
The function name is IEnumerable<SendSmPDU> GetPDUs(DataCoding defaultEncoding)
//protected override IEnumerable<SendSmPDU> GetPDUs(DataCoding defaultEncoding)
//{
// //This smpp implementation does not support sending concatenated messages,
// //however, concatenated messages are supported on the receiving side.
// int maxLength = GetMaxMessageLength(defaultEncoding, false);
// byte[] bytes = SMPPEncodingUtil.GetBytesFromString(vText, defaultEncoding);
// //Check message size
// if(bytes.Length > maxLength)
// {
// throw new InvalidOperationException(string.Format(
// "Encoding '{0}' does not support messages of length greater than '{1}' charactors",
// defaultEncoding, maxLength));
// }
// SubmitSm sm = new SubmitSm();
// sm.SetMessageBytes(bytes);
// sm.SourceAddress.Address = vSourceAddress;
// sm.DestinationAddress.Address = vDestinatinoAddress;
// sm.DataCoding = defaultEncoding;
// if (vRegisterDeliveryNotification) { sm.RegisteredDelivery = RegisteredDelivery.DeliveryReceipt; }
// yield return sm;
//}
protected override IEnumerable<SendSmPDU> GetPDUs(DataCoding defaultEncoding)
{
SubmitSm sm = new SubmitSm();
sm.SourceAddress.Address = vSourceAddress;
sm.DestinationAddress.Address = vDestinatinoAddress;
sm.DataCoding = defaultEncoding;
if (vRegisterDeliveryNotification)
sm.RegisteredDelivery = RegisteredDelivery.DeliveryReceipt;
int maxLength = GetMaxMessageLength(defaultEncoding, false);
byte[] bytes = SMPPEncodingUtil.GetBytesFromString(vText, defaultEncoding);
if (bytes.Length > maxLength)
{
var SegID = new Random().Next(1000, 9999);
var messages = Split(vText, GetMaxMessageLength(defaultEncoding, true));
var totalSegments = messages.Count;
var udh = new Udh(SegID, totalSegments, 0);
for (int i = 0; i < totalSegments; i++)
{
udh.MessageSequence = i + 1;
sm.Header.SequenceNumber = PDUHeader.GetNextSequenceNumber();
sm.SetMessageText(messages[i], defaultEncoding, udh);
yield return sm;
}
}
else
{
sm.SetMessageBytes(bytes);
yield return sm;
}
}
private static List<String> Split(string message, int maxPartLength)
{
var result = new List<String>();
for (int i = 0; i < message.Length; i += maxPartLength)
{
var chunkSize = i + maxPartLength < message.Length ? maxPartLength : message.Length - i;
var chunk = new char[chunkSize];
message.CopyTo(i, chunk, 0, chunkSize);
result.Add(new string(chunk));
}
return result;
}

Resources