How to pass value from Controller to View (Just In Time/Async) - asp.net

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

Related

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"];
}

Decompress stream from HttpClient using SharpZipLib in 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);

Windows Store App HttpClient progress

I need to provide the download progress inside the app for an arbitrary file.
I thought I could use HttpClient.GetInputStreamAsync progress but it is not fine grained. The progress notification is delivered very rare. The code below:
var httpClient = new HttpClient();
var path = new Uri(#"http://<path>");
using (var inputStream = (await httpClient.GetInputStreamAsync(path).AsTask(new MyProgress())).AsStreamForRead())
{
var outputFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("output.mov", CreationCollisionOption.ReplaceExisting);
using (var outputStream = (await outputFile.OpenAsync(FileAccessMode.ReadWrite)).AsStreamForWrite())
{
await inputStream.CopyToAsync(outputStream);
await outputStream.FlushAsync();
}
}
Debug.WriteLine("done");
private class MyProgress : IProgress<HttpProgress>
{
public void Report(HttpProgress value)
{
Debug.WriteLine("HTTP {0} progress {1}/{2}", value.Stage, value.BytesReceived, value.TotalBytesToReceive);
}
}
outputs:
HTTP ResolvingName progress 0/
HTTP ConnectingToServer progress 0/
HTTP SendingHeaders progress 0/
HTTP WaitingForResponse progress 0/
HTTP ReceivingHeaders progress 0/
HTTP ReceivingContent progress 0/109192147
done
So at some point of time the total bytes to receive is known but no progress reported during file download.
I ended up with solution like below:
var httpClient = new HttpClient();
var path = new Uri(#"http://<path>");
var progressHelper = new ProgressHelper();
using (var inputStream = (await httpClient.GetInputStreamAsync(path).AsTask(progressHelper)).AsStreamForRead())
{
var outputFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("output.mov", CreationCollisionOption.ReplaceExisting);
using (var outputStream = (await outputFile.OpenAsync(FileAccessMode.ReadWrite)).AsStreamForWrite())
{
var buffer = new byte[1024 * 1024];
int read;
while ((read = await inputStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
progressHelper.BytesReceived += (ulong)read;
await outputStream.WriteAsync(buffer, 0, read);
}
await outputStream.FlushAsync();
}
}
Debug.WriteLine("done");
private class ProgressHelper : IProgress<HttpProgress>
{
private ulong _bytesReceived = 0;
private ulong? _totalBytesToReceive = null;
public void Report(HttpProgress value)
{
Debug.WriteLine("HTTP {0} progress {1}/{2}", value.Stage, value.BytesReceived, value.TotalBytesToReceive);
TotalBytesToReceive = value.TotalBytesToReceive;
}
public ulong? TotalBytesToReceive
{
get
{
return _totalBytesToReceive;
}
set
{
if (_totalBytesToReceive == value)
return;
_totalBytesToReceive = value;
UpdateProgress();
}
}
public ulong BytesReceived
{
get
{
return _bytesReceived;
}
set
{
if (_bytesReceived == value)
return;
_bytesReceived = value;
UpdateProgress();
}
}
public int? Progress
{
get
{
if (_totalBytesToReceive.HasValue)
{
return (int)Math.Round((100.0 * _bytesReceived) / _totalBytesToReceive.Value);
}
return null;
}
}
private void UpdateProgress()
{
Debug.WriteLine("Progress: {0}", Progress);
}
}
Since the HttpClient.GetInputStreamAsync doesn't support progress during file download, you can use other methods of HttpClient such as GetAsync andGetBufferAsync.The following code is updating of your code to use HttpClient.GetAsync.
var httpClient = new HttpClient();
var path = new Uri("https://sec.ch9.ms/slides/developerGuideToWindows10/02-XAMLcontrols.pptx");
HttpResponseMessage response = await httpClient.GetAsync(path).AsTask(new MyProgress());
using (Stream responseStream = (await response.Content.ReadAsInputStreamAsync()).AsStreamForRead())
{
var outputFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("output.pptx", CreationCollisionOption.ReplaceExisting);
using (var outputStream = (await outputFile.OpenAsync(FileAccessMode.ReadWrite)).AsStreamForWrite())
{
await responseStream.CopyToAsync(outputStream);
await outputStream.FlushAsync();
}
}
Debug.WriteLine("done");
And the outputs

Xamarin Forms - Resize Camera Picture

Someone helped me get this code for taking a picture using xamarin forms labs camera:
picker = DependencyService.Get<IMediaPicker> ();
task = picker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 800,
});
img.BackgroundColor = Color.Gray;
Device.StartTimer (TimeSpan.FromMilliseconds (250), () => {
if (task != null) {
if (task.Status == TaskStatus.RanToCompletion) {
Device.BeginInvokeOnMainThread (async () => {
//img.Source = ImageSource.FromStream (() => task.Result.Source);
var fileAccess = Resolver.Resolve<IFileAccess> ();
string imageName = "img_user_" + User.CurrentUser().id + "_" + DateTime.Now.ToString ("yy_MM_dd_HH_mm_ss") + ".jpg";
fileName = imageName;
fileAccess.WriteStream (imageName, task.Result.Source);
fileLocation = fileAccess.FullPath(imageName);
FileStream fileStream = new FileStream(fileAccess.FullPath(imageName), FileMode.Open, System.IO.FileAccess.Read);
imageUrl = (string)test[0]["url"];
img.Source = imageUrl;
});
}
return task.Status != TaskStatus.Canceled
&& task.Status != TaskStatus.Faulted
&& task.Status != TaskStatus.RanToCompletion;
}
return true;
});
It saves the image, but the actual size of the phone picture taken is huge, is there a way to resize it.
UPDATE: The original answer is not useful, see below for updated answer. The issue was the PCL library was very slow and consumed too much memory.
ORIGINAL ANSWER (do not use):
I found an image I/O library, ImageTools-PCL, which I forked on github and trimmed down what wouldn't compile in Xamarin, keeping the modifications to minimum and the result seems to work.
To use it download the linked repository, compile it with Xamarin and add the DLLs from Build folder to your Forms project.
To resize an image you can do this (should fit the context of your question)
var decoder = new ImageTools.IO.Jpeg.JpegDecoder ();
ImageTools.ExtendedImage inImage = new ImageTools.ExtendedImage ();
decoder.Decode (inImage, task.Result.Source);
var outImage = ImageTools.ExtendedImage.Resize (inImage, 1024, new ImageTools.Filtering.BilinearResizer ());
var encoder = new ImageTools.IO.Jpeg.JpegEncoder ();
encoder.Encode (outImage, fileAccess.CreateStream (imageName));
ImageSource imgSource = ImageSource.FromFile (fileAccess.FullPath (imageName));
UPDATED ANSWER:
Get Xamarin.XLabs from nuget, learn about using Resolver, create an IImageService interface with Resize method.
Implementation for iOS:
public class ImageServiceIOS: IImageService{
public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
{
if (File.Exists(sourceFile) && !File.Exists(targetFile))
{
using (UIImage sourceImage = UIImage.FromFile(sourceFile))
{
var sourceSize = sourceImage.Size;
var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
if (!Directory.Exists(Path.GetDirectoryName(targetFile)))
Directory.CreateDirectory(Path.GetDirectoryName(targetFile));
if (maxResizeFactor > 0.9)
{
File.Copy(sourceFile, targetFile);
}
else
{
var width = maxResizeFactor * sourceSize.Width;
var height = maxResizeFactor * sourceSize.Height;
UIGraphics.BeginImageContextWithOptions(new CGSize((float)width, (float)height), true, 1.0f);
// UIGraphics.GetCurrentContext().RotateCTM(90 / Math.PI);
sourceImage.Draw(new CGRect(0, 0, (float)width, (float)height));
var resultImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
if (targetFile.ToLower().EndsWith("png"))
resultImage.AsPNG().Save(targetFile, true);
else
resultImage.AsJPEG().Save(targetFile, true);
}
}
}
}
}
Implementation of the service for Android:
public class ImageServiceDroid: IImageService{
public void ResizeImage(string sourceFile, string targetFile, float maxWidth, float maxHeight)
{
if (!File.Exists(targetFile) && File.Exists(sourceFile))
{
// First decode with inJustDecodeBounds=true to check dimensions
var options = new BitmapFactory.Options()
{
InJustDecodeBounds = false,
InPurgeable = true,
};
using (var image = BitmapFactory.DecodeFile(sourceFile, options))
{
if (image != null)
{
var sourceSize = new Size((int)image.GetBitmapInfo().Height, (int)image.GetBitmapInfo().Width);
var maxResizeFactor = Math.Min(maxWidth / sourceSize.Width, maxHeight / sourceSize.Height);
string targetDir = System.IO.Path.GetDirectoryName(targetFile);
if (!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
if (maxResizeFactor > 0.9)
{
File.Copy(sourceFile, targetFile);
}
else
{
var width = (int)(maxResizeFactor * sourceSize.Width);
var height = (int)(maxResizeFactor * sourceSize.Height);
using (var bitmapScaled = Bitmap.CreateScaledBitmap(image, height, width, true))
{
using (Stream outStream = File.Create(targetFile))
{
if (targetFile.ToLower().EndsWith("png"))
bitmapScaled.Compress(Bitmap.CompressFormat.Png, 100, outStream);
else
bitmapScaled.Compress(Bitmap.CompressFormat.Jpeg, 95, outStream);
}
bitmapScaled.Recycle();
}
}
image.Recycle();
}
else
Log.E("Image scaling failed: " + sourceFile);
}
}
}
}
#Sten's answer might encounter out-of-memory problem on some android devices. Here's my solution to implement the ResizeImage function
, which is according to google's "Loading Large Bitmaps Efficiently" document:
public void ResizeImage (string sourceFile, string targetFile, int reqWidth, int reqHeight)
{
if (!File.Exists (targetFile) && File.Exists (sourceFile)) {
var downImg = decodeSampledBitmapFromFile (sourceFile, reqWidth, reqHeight);
using (var outStream = File.Create (targetFile)) {
if (targetFile.ToLower ().EndsWith ("png"))
downImg.Compress (Bitmap.CompressFormat.Png, 100, outStream);
else
downImg.Compress (Bitmap.CompressFormat.Jpeg, 95, outStream);
}
downImg.Recycle();
}
}
public static Bitmap decodeSampledBitmapFromFile (string path, int reqWidth, int reqHeight)
{
// First decode with inJustDecodeBounds=true to check dimensions
var options = new BitmapFactory.Options ();
options.InJustDecodeBounds = true;
BitmapFactory.DecodeFile (path, options);
// Calculate inSampleSize
options.InSampleSize = calculateInSampleSize (options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.InJustDecodeBounds = false;
return BitmapFactory.DecodeFile (path, options);
}
public static int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight)
{
// Raw height and width of image
int height = options.OutHeight;
int width = options.OutWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
int halfHeight = height / 2;
int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
You can do this natively for each platform and use an interface. Heres an example for IOS
In your PCL project you need to add an interface
public interface IImageResizer
{
byte[] ResizeImage (byte[] imageData, double width, double height);
}
Then to resize an image in your code, you can load the IOS implementation of that interface using the DependencyService and run the ResizeImage method
var resizer = DependencyService.Get<IImageResizer>();
var resizedBytes = resizer.ResizeImage (originalImageByteArray, 400, 400);
Stream stream = new MemoryStream(resizedBytes);
image.Source = ImageSource.FromStream(stream);
IOS Implementation, add this class to your IOS project.
[assembly: Xamarin.Forms.Dependency (typeof (ImageResizer_iOS))]
namespace YourNamespace
{
public class ImageResizer_iOS : IImageResizer
{
public byte[] ResizeImage (byte[] imageData, double maxWidth, double maxHeight)
{
UIImage originalImage = ImageFromByteArray (imageData);
double width = 300, height = 300;
double maxAspect = (double)maxWidth / (double)maxHeight;
double aspect = (double)originalImage.Size.Width/(double)originalImage.Size.Height;
if (maxAspect > aspect && originalImage.Size.Width > maxWidth) {
//Width is the bigger dimension relative to max bounds
width = maxWidth;
height = maxWidth / aspect;
}else if (maxAspect <= aspect && originalImage.Size.Height > maxHeight){
//Height is the bigger dimension
height = maxHeight;
width = maxHeight * aspect;
}
return originalImage.Scale(new SizeF((float)width,(float)height)).AsJPEG ().ToArray ();
}
public static MonoTouch.UIKit.UIImage ImageFromByteArray(byte[] data)
{
if (data == null) {
return null;
}
MonoTouch.UIKit.UIImage image;
try {
image = new MonoTouch.UIKit.UIImage(MonoTouch.Foundation.NSData.FromArray(data));
} catch (Exception e) {
Console.WriteLine ("Image load failed: " + e.Message);
return null;
}
return image;
}
}
}
An update from the Xamarin Media Plugin allows you to resize the image
https://github.com/jamesmontemagno/MediaPlugin
... barring that, and you need a more generic resize option (say the image comes from a web call, and not the device, then have a look at:
https://github.com/InquisitorJax/Wibci.Xamarin.Images

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