Uploading a photo stream from camera into azure blob in WP7 - silverlight

I have the following simple application page that uses the phone camera to upload the taken photo to azure blob:
public partial class AddReport : PhoneApplicationPage
{
// blobs stuff
string storageAccount = "MYACCOUNT";
string storageKey = "MYKEY";
string blobServiceUri = "http://MYACCOUNT.blob.core.windows.net";
CloudBlobClient blobClient;
private Report newReport;
public AddReport()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
//base.OnNavigatedTo(e);
newReport = new Report();
var credentials = new StorageCredentialsAccountAndKey(storageAccount, storageKey);
blobClient = new CloudBlobClient(blobServiceUri, credentials);
}
private void TakePhotoClick(object sender, EventArgs eventArgs)
{
//The camera chooser used to capture a picture.
CameraCaptureTask ctask;
//Create new instance of CameraCaptureClass
ctask = new CameraCaptureTask();
//Create new event handler for capturing a photo
ctask.Completed += new EventHandler<PhotoResult>(ctask_Completed);
//Show the camera.
ctask.Show();
}
void ctask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK && e.ChosenPhoto != null)
{
WriteableBitmap CapturedImage = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
UploadToBlobContainer(e.ChosenPhoto);
}
else
{
//user decided not to take a picture
}
}
private void UploadToBlobContainer(System.IO.Stream stream)
{
string containerName = "reportsPhotos";
var container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExist(true, r =>
Dispatcher.BeginInvoke(() =>
{
var blobName = "report" + newReport.ReportId.ToString();
var blob = container.GetBlobReference(blobName);
blob.Metadata["ReportId"] = newReport.ReportId.ToString();
blob.UploadFromStream(stream, r2 =>
Dispatcher.BeginInvoke(() =>
{
newReport.Photo = container.Uri + "/" + blobName;
}));
}));
}
}
This is a simple case and I am not using SAS to authenticate, instead I save the key in the app itself (this is only for testing purposes) and also my blobs are publicly available.
when I run in debug mode it seems that everything is working, but the photo doesn't get uploaded to the blob. Also, I don't know how I can debug this to see if there was any error from the blob service.
Can anyone tell me what might be wrong ?
EDIT1: it seems that the container is not being created either. i've confirmed this using azure blob explorer
EDIT2: I am getting a System.Net.WebException : "The remote server returned an error: NotFound."

After long hours I have finally discovered that the problem was with this line:
string containerName = "reportsPhotos";
According to here all letters in a container name must be lowercase.
Changing it to reportsphotos solved the issue
That was time well spent.

Can you try just doing it like this instead:
// Retrieve storage account from connection-string
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
RoleEnvironment.GetConfigurationSettingValue("StorageConnectionString"));
// Create the blob client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
// Retrieve reference to a blob named "myblob"
CloudBlob blob = container.GetBlobReference("myblob");
// Create or overwrite the "myblob" blob with contents from a local file
using (var fileStream = System.IO.File.OpenRead(#"path\myfile"))
{
blob.UploadFromStream(fileStream);
}
This is from:
http://www.windowsazure.com/en-us/develop/net/how-to-guides/blob-storage/#upload-blob

Related

Injecting serverside data when using ISpaBuilder.UseReactDevelopmentServer

When using ASP.NET (Core, .NET 5) MVC's IApplicationBuilder.UseSpa / ISpaBuilder.UseReactDevelopmentServer (in development), is there a way to postprocess the index HTML before it's sent to the browser? I need to inject a script tag holding data about the currently auth'd user to be consumed by the React app.
I want to avoid having to do an extra call from inside my React app just to get the currently logged on user at startup.
You can use custom middleware to do that. Assuming you're on .net core 3.1, the middleware would look something along these lines:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace TestReactDevServer.Middleware
{
public class ScriptInjectorMiddleware
{
private readonly RequestDelegate _next;
public ScriptInjectorMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
//Save pointer to the original response body stream
var originalBodyStream = context.Response.Body;
//Create new memory stream
using (var responseBody = new MemoryStream())
{
//...and use it for subsequent requests so we can peek the contents
context.Response.Body = responseBody;
//Continue down the Middleware pipeline, eventually returning to this class
await _next(context);
//inspect response, inject script
await InjectScript(responseBody, "window.myUser='123';");
//copy the contents of the new memory stream to the original place
await responseBody.CopyToAsync(originalBodyStream);
}
}
private async Task<Stream> InjectScript(Stream input, string script)
{
input.Seek(0, SeekOrigin.Begin);
var decompressed = new MemoryStream();
using (var tmp = new GZipStream(input, CompressionMode.Decompress, true))
{
tmp.CopyTo(decompressed);
}
var html = await decompressed.StreamToString();
var modifiedHtml = Regex.Replace(html, "</body>[\\n\\r]+</html>", $"<script type=\"text/javascript\">{script}</script></body></html>", RegexOptions.IgnoreCase | RegexOptions.Multiline); // any way to locate closing tags will work here, you probably can be more efficient
input.Seek(0, SeekOrigin.Begin);
using (var modifiedHtmlStream = modifiedHtml.ToStream())
using (var tmp = new GZipStream(input, CompressionMode.Compress, true)) // might be optional
{
modifiedHtmlStream.CopyTo(tmp);
}
return input;
}
}
public static class ScriptInjectorMiddlewareExtensions
{
public static IApplicationBuilder UseScriptInjectorMiddleware(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<ScriptInjectorMiddleware>();
}
}
public static class StreamExtensions {
public static async Task<string> StreamToString(this Stream stream) {
stream.Seek(0, SeekOrigin.Begin);
return await new StreamReader(stream).ReadToEndAsync();
}
public static Stream ToStream(this string str)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
}
}
a couple of things to point out:
Testing this with Chrome, I ended up having to decompress the proxied response and compress it back after modification - I think compression step might be optional.
Depending on your user agent you might need to handle more compression cases (see more examples on Github)
You will need to inject this middleware before your call to .UseSpa() in Startup.cs: adding app.UseUserInjectorMiddleware(); should pick up the included extension method
I suspect this example is far from being complete, especially in terms of handling different encodings and content types - I am hoping you'd be able to adapt the idea to your use case.

Listen for callbacks in dotNetBrowser

How can I use dotnetbrowser doing the following in a winform application?
Create a listener that listen for callbacks to a specific redirect url.
Open url in dotnetbrowser. The url makes the callback to the redirect url in another thread
The listener catches the response from the callback.
I can do this with an ordinary webbrowser, but I would like it to be silent. That's why I try to use dotnetbrowser instead.
Is dotNetBrowser a good choice for this, or is there a better option?
This is from my test code with a non silent webbrowser. First I create a listener that listen to a redirectUri:
var listener = new HttpListener();
listener.Prefixes.Add(redirectURI);
listener.Start();
Then I start the url in a webbrowser:
Process p = Process.Start(url);
The started url will send a callback to the redirectUri. The listener will get it.
var context = await listener.GetContextAsync(); ;
string formData = string.Empty;
using (var body = context.Request.InputStream)
{
using (var reader = new System.IO.StreamReader(body, context.Request.ContentEncoding))
{
formData = reader.ReadToEnd();
}
}
listener.Close();
I found a solution with help from dotnetbrowser support site.
This is the winform constructor in my new test project:
public Form1()
{
webView = new BrowserView() { Dock = DockStyle.Fill };
Task.Run(() =>
{
engine = EngineFactory.Create(new EngineOptions.Builder
{
RenderingMode = RenderingMode.HardwareAccelerated,
LicenseKey = "your license key here"
}
.Build());
browser = engine.CreateBrowser();
})
.ContinueWith(t =>
{
webView.InitializeFrom(browser);
var listener = new HttpListener();
listener.Prefixes.Add(redirectURI);
listener.Start();
browser.Navigation.LoadUrl(url);
var context = listener.GetContextAsync().GetAwaiter().GetResult();
//Get data from redirectUri. You find this code from test example above, but not really relevant for the problem.
var formData = GetRequestPostData(context.Request);
listener.Close();
}, TaskScheduler.FromCurrentSynchronizationContext());
InitializeComponent();
FormClosing += Form1_FormClosing;
Controls.Add(webView);
this.Visible = false;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
browser?.Dispose();
engine?.Dispose();
}

Web api large file download with HttpClient

I have a problem with large file download from the web api to the win forms app. On the win form app I'm using HttpClient for grabbing data. I have following code on server side:
[HttpPost]
[Route]
public async Task<HttpResponseMessage> GetBackup(BackupRequestModel request)
{
HttpResponseMessage response;
try
{
response = await Task.Run<HttpResponseMessage>(() =>
{
var directory = new DirectoryInfo(request.Path);
var files = directory.GetFiles();
var lastCreatedFile = files.OrderByDescending(f => f.CreationTime).FirstOrDefault();
var filestream = lastCreatedFile.OpenRead();
var fileResponse = new HttpResponseMessage(HttpStatusCode.OK);
fileResponse.Content = new StreamContent(filestream);
fileResponse.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return fileResponse;
});
}
catch (Exception e)
{
logger.Error(e);
response = Request.CreateResponse(HttpStatusCode.InternalServerError);
}
return response;
}
on client side:
private async void btnStart_Click(object sender, EventArgs e)
{
var requestModel = new BackupRequestModel();
requestModel.Username = txtUsername.Text;
requestModel.Password = txtPassword.Text;
requestModel.Path = txtServerPath.Text;
var client = new HttpClient();
var result = await client.PostAsJsonAsync("http://localhost:50116/api/backup", requestModel);
var stream = await result.Content.ReadAsStreamAsync();
var localPath = #"d:\test\filenew.bak";
var fileStream = File.Create(localPath);
stream.CopyTo(fileStream);
fileStream.Close();
stream.Close();
fileStream.Dispose();
stream.Dispose();
client.Dispose();
}
}
This is actually working, but the purpose of this program is to grab large files over 3GB and save it to the client.
I have tried this on files sized 630MB what I notice is: When I call web api with http client, http client actually loads 630MB in the memory stream, and from the memory stream to the file stream, but when I try to load a different file I'm getting OutOfMemoryException. This is happening because the application doesn't release memory from the previous loaded file. I can see in task manager that it is holding 635MB of ram memory.
My question is how can I write data directly from HttpClient to file without using memory stream, or in other words how can I write data to file while HttpClient is downloading data?
To make the request, use a SendAsync overload that allows you to specify a HttpCompletionOption and use ResponseHeadersRead. You'll have to manually build the request though, without using the PostAsJsonAsync convenience method.

WP7 HttpWebRequest how to know when multiple requests are completed?

Description:
I have multiple successive image downloads and saving in IsolatedStorage using HttpWebRequest.
After all image downloadsa are completed I need to navigate user to another page, where images are displayed in image controls from isolated storage.
Question:
How can I know when all the downloads are completed to run the navigation?
I tried to pass the redirect to the requests callback function (requestImage_BeginGetResponse()) in the last foreach loops iteration after saving the image,
but the images are different sizes and sometimes the last image downloads faster than previous, that results in redirect before all downloads are completed.
the code:
private HttpWebRequest request;
private void downloadDataFile()
{
...
foreach (Gallery image in gallery)
{
request = (HttpWebRequest)WebRequest.Create(image.url);
request.BeginGetResponse(new AsyncCallback(requestImage_BeginGetResponse), new object[] { request, image.name });
}
}, request);
}
private void requestImage_BeginGetResponse(IAsyncResult r)
{
object[] param = (object[])r.AsyncState;
HttpWebRequest httpRequest = (HttpWebRequest)param[0];
string filename = (string)param[1];
HttpWebResponse httpResoponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
System.Net.HttpStatusCode status = httpResoponse.StatusCode;
if (status == System.Net.HttpStatusCode.OK)
{
Stream str = httpResoponse.GetResponseStream();
Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
{
saveImage(str, filename);
}));
}
}
You should prepare a int type variable to record your images that would be downloaded.Whenever a image is downloaded,make the variable minus 1 untill its value is 0,and notify the navigating operation.

Facebook Album Picture using Facebook C# SDK

I'm tring to get an album picture from facebook using the facebook C# SDK within Silverlight app with the following code:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.GetAsync(string.Format("/{0}/picture?type=small", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e;
};
Where this.ID is the ID of the album, but I get this error:
Unexpected character encountered while parsing value: �. Line 1, position 1.
from the DeserializeObject method in the JsonSerializer. The problem is that facebook does'n return json data with the imge uri or something like this, but they actually return the image itself in a binary data. Anybody has any idea how I can handle this result or just get Uri to the image?
I have a workaround for this using this code:
var request = WebRequest.Create(string.Format("https://graph.facebook.com/{0}/picture?access_token={1}", this.ID, this.Profile.AccessToken));
request.BeginGetResponse(ar =>
{
using (var response = ((WebRequest)ar.AsyncState).EndGetResponse(ar))
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
this.Picture = new BitmapImage(new Uri(response.ResponseUri.AbsoluteUri));
}
);
}
}, request);
But I really wanted to use only Facebook C# SDK for getting the data.
Here is the solution that I'm going to use:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.QueryAsync(String.Format("SELECT src_small, src_big, src FROM photo WHERE pid IN (SELECT cover_pid FROM album WHERE object_id={0})", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e.GetResultData();
Deployment.Current.Dispatcher.BeginInvoke(() => this.Picture = result[0].src_small);
};
I was facing a similar issue. Wanted to use Facebook C# SDK only as well.
Solved it like this:
FacebookClient facebookAlbumClient = new FacebookClient(_albumAccessToken);
dynamic facebookAlbumCover = facebookAlbumClient.Get(string.Format("/{0}?fields=picture&type=thumbnail", (string)facebookAlbum["id"]));
This way you are getting the json array and not the picture
I think I found an acceptable solution for my problem. I'll just use FQL instead of Graph API. This will do the job:
FacebookClient client = new FacebookClient(this.Profile.AccessToken);
client.QueryAsync(String.Format("SELECT src_small, src_big, src FROM photo WHERE pid IN (SELECT cover_pid FROM album WHERE object_id={0})", this.ID));
client.GetCompleted += (s, e) =>
{
dynamic result = e.GetResultData();
Deployment.Current.Dispatcher.BeginInvoke(() => this.Picture = result[0].src_small);
};

Resources