Form POST data is lost in ASP.NET MVC - wcf

I have ASP.NET MVC 4. Just recently I upgraded to .NET Framework 4.5, VS 2012, and I believe it also upgraded IIS express to version 8.
Now that I upgraded, my application looses POST data. In one of my WCF components I look into HttpContext.Current.Request.Form -- it now gives me 0 fields, while I expect 4 fields. For troubleshooting, I added HttpModule with an empty body, and if I break on BeginRequest, I consistently can see all my form fields in HttpContext.Current.Request.Form from HttpModule, but when I hit F5, I sometimes get the Form fields in the component and sometimes the Forms objects is empty.
Sounds like some kind of race condition inside of ASP.NET, MVC or something.
I am at a loss.

I suggest you inspect you POST with an HTTP sniffer such as Fiddler and see if the post is being sent correctly.
Sometimes you are sending the POST with an incorrect encoding and it might also cause you issues like that.
If after inspecting the POST with Fiddler and making sure you are using the correct encoding you still canĀ“t find what's wrong I suggest you create a small piece of code that reproduces the error so we can better help you.

Related

Serilog using EnrichDiagnosticContext with additional properties not being logged in SignalR Hub

I have recently implemented Serilog logging into my ASP.NET Core/.NET5 web app that uses SignalR. I'm using the Elasticsearch sink and everything is largely working as expected. I decided to add some additional HttpContext properties to be logged on each request, so I went down the road of extending the call to UseSerilogRequestLogging() in StartUp.cs as to enrich the diagnostic context with a couple of extra properties (mainly because this seemed like the simplest way to do it):
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("HttpRequestClientIP", httpContext.Connection.RemoteIpAddress);
diagnosticContext.Set("UserName", httpContext.User?.Identity?.Name == null ? "(anonymous)" : httpContext.User.Identity.Name);
};
});
At first, this seemed to work as expected until I noticed it wasn't always working. I really want the extra properties logged on all log records written, and it seems to work fine on log records that are written automatically by Serilog when typical HTTP GETs, HTTP POSTs, etc. occur... But in my Signalr Hub class, I have a couple of places where I'm manually writing my own log records like Logger.Log(LogLevel.Information, "whatever.."), but these extra properties are simply not there on these records.
What am I missing here? Is it something about this being in a Signalr Hub that makes them unavailable? Or perhaps there's something I'm doing wrong with my Logger.Log() calls?
Any ideas would be appreciated.
Thanks-
It's not gonna to work with signalR.
Behind the screen, app.UseSerilogRequestLogging make use of a middleware in the request pipeline, that call RequestLoggingMiddleware as what you can see in detail here.
SignalR use the first Http request to setting to connection up to websocket, which won't goes through the pipeline at all. Therefore, doesn't have anything to do with RequestLoggingMiddleware, which you are using to logging out the request.
I finally ended up going with a couple of custom Enrichers. I did experiment briefly with middleware vs enrichers and they both seem to work as expected. Both always added the additional properties to all log entries. I'm still not quite sure I understand why the DiagnosticContext option behaves the way it does, unless it is simply due to the logging in question being in a SignalR hub as #Gordon Khanh Ng. posted. If that were the root of the problem though, you wouldn't think the enrichers or middleware would work either.

Sending xAPI statements to an LRS

I'm trying to send xAPI statements from an "Activity Provider" to the ADL LRS live demo. The goal is to implement this from my C# .NET application, but I was having trouble implementing it so I tried running a simple POST request from JMeter.
I do get a 200 response, but when I try to check whether the statement was successfully stored at https://lrs.adlnet.gov/me/statements, it's empty.
Am I completely misunderstanding how this structure is supposed to work? I'm going to install the ADL LRS eventually for testing purposes, but I wanted to get the actual request structure worked out first.
The path looks incorrect, the POST should be to {endpoint}/statements, so in your case it looks like it should be https://lrs.adlnet.gov/xAPI/statements. Additionally you should make sure you are setting the X-Experience-API-Version header. If this doesn't solve the issue, you should look at more than just the response status code, and see what the body contains (and add it to your question). The body for the type of request you are sending should return JSON, with an array with a single statement identifier in it. Additionally when you retrieve the statements the URL you use should match the one that you specify when you send, so /me/ is not correct.
If it is a basic C# .NET project you may be interested in https://github.com/RusticiSoftware/TinCan.NET. It is showing its age, but in general for a number of projects it will still work or would at least be a reasonable place to start.

How to use HttpResponseFeature in a ASP.net Core Middleware

I just found out that "RequestFeatures" is a thing in ASP.net Core, news to me..
Anyways..
I have created a middleware that needs to alter the response body and the headers provided with the response.
Im used to do this by alterntiv it directly on the HttpContext context-object provided as an argument to the Invoke-method.. however I read somewhere that context.Features is the way to go due to optimizations and what not.. (is this true?, I get that its alot easiter to test the Features, than to "mock" an entire HttpContext which has been historically a painful thing to do..) So I created my own implementation of the HttpResponseFeature and registred it in my Invoke method using:
httpContext.Features.Set<IHttpResponseFeature>
(
//Registering my own HttpResponseFeature that takes an argument..
new MyHttpResponseFeature(httpResponseMessage)
);
However, the OnCompleted or the OnStarting-methods never runs. I have added a few breakpoints to validate this, but the breakpoints are never hit. Am I missing something?
Turns out that the FeatureCollection/RequestFeatures is a "new" thing if your building your very own custom HTTP server ontop of ASP.net Core.
An article that covers this fairly well is this one:
https://reynders.co/use-iserver-from-aspnet-core-to-create-your-own-web-server/

MVC4- An asynchronous operation cannot be started at this time --- code works fine on MVC3

I converted a project from MVC3 to MVC4 and also from Entity Framework 5 to EF 6.1. In the code there is a VBHTML page that has a code section "Using Html.BeginForm.... end using". in this page, a user can select a file and click submit. That calls a POST method in a controller. The method in the controller uploads the selected file to Google drive using resumable uploader (aynchronous) of GData API. ResumableUploader has to be used (GData API restrictions for uploading PDF and big files). Now, this code has always worked in the past in MVC3. As soon as the platform was changed to MVC4, started getting this exception:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>
at System.Web.AspNetSynchronizationContext.OperationStarted() at Google.GData.Client.ResumableUpload.ResumableUploader.AsyncStarter
(AsyncResumableUploadData data, WorkerResumableUploadHandler workerDelegate,
Object userData)
I did put #Page Async="true" in the VBHTML page, but that did not help. I am 100% sure this is related to MVC4 and/or .Net 4.5 because no other change has been done in the code (other than moving to MVC4 and moving to .Net4.5). I have two code branches now, one on MVC3 and one on MVC4. When I compile MVC3 and copy the output DLL in the app, the above issue does not surface. When I replace that DLL by MVC4 version, the above issue comes up. How to handle this?
This is the code that causes this issue:
Dim auth As Authenticator = New AuthSubAuthenticator("MyToken", authFactory.Token)
Dim uploader As New ResumableUploader(10485760)
AddHandler uploader.AsyncOperationCompleted, AddressOf UploaderCompleted
uploader.InsertAsync(auth, file, New Object())
The trace shows that the exception was thrown from the last line (uploader.InsertAsync)
I understand there is a await method that I could use. Did not try, instead, changed uploader.InsertAsync to uploader.Insert and the code works ok. But but the user has to wait until the upload is complete (for bigger files, for quite a while).
I am 100% sure this is related to MVC4 and/or .Net 4.5
Yes, this is a change in ASP.NET 4.5. However, it's important to note that the code was technically wrong before. ASP.NET 4.5 adds several safeguards to catch improper asynchronous usage. So, the MVC3 code was actually improper; it just wasn't getting caught and reported as such.
changed uploader.InsertAsync to uploader.Insert and the code works ok. But but the user has to wait until the upload is complete (for bigger files, for quite a while).
This is the "proper" way to do it on ASP.NET (on a side note, using await would be more efficient than Insert). ASP.NET is not designed to do work without a user connection.
Consider, for example, what would happen if the upload errors out; there's no way to notify the user that the upload in fact did not complete. For that matter, there's no way to notify the user that the upload did complete. Also, ASP.NET may recycle your application, which can kill an in-progress upload. For these reasons, doing "fire and forget" work is not recommended on ASP.NET.
However, if you're willing to live with those limitations, I describe on my blog a variety of ways to do fire and forget on ASP.NET. Note that ASP.NET 4.5.2 added a built-in way to do this: HostingEnvironment.QueueBackgroundWorkItem.

how to get errors from tileupdatemanager

In my winrt app, I am trying to update the live tile based on polled URIs. There is currently no update happening and I can't figure out how to troubleshoot. There are numerous scenarios that could be breaking things but i can't seem to find anyway to get insight into potential errors.
The TileUpdateManager seems to be a bit of a black hole that absorbs information but never lets it out.
Does anyone know of how to view errors from the TileUpdateManager?
If it interests anyone, here is my update code:
TileUpdateManager.CreateTileUpdaterForApplication().EnableNotificationQueue(true);
PeriodicUpdateRecurrence recurrence = PeriodicUpdateRecurrence.HalfHour;
List<Uri> urisToPoll = new List<Uri>();
urisToPoll.Add(new Uri(#"http://livetileservice2012.azurewebsites.net/api/liveupdate/1"));
urisToPoll.Add(new Uri(#"http://livetileservice2012.azurewebsites.net/api/liveupdate/2"));
TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdateBatch(urisToPoll, recurrence);
To expand on Nathan's comment, here are two steps you can take to troubleshoot:
Enter your URI straight into a browser to see the results that are returned, and inspect them for being proper XML. As Nathan points out, your URIs are returning JSON which will be ignored by the tile update manager. As a working example (that I use in Chapter 13 of my HTML/JS book), try http://programmingwin8-js-ch13-hellotiles.azurewebsites.net/Default.cshtml.
If you feel that your URI is returning proper XML, try it in the Push and Periodic Notifications Sample (Scenarios 4 and 5 for tiles and badges). If this works, then the error would be in your app code and not in the service.
Do note that StartPeriodicUpdate[Batch] will send a request to the service right away, rather than waiting for the first interval to pass.
Also, if you think that you might have a problem with the service, it's possible to step through its code using Visual Studio Express for Web running on the localhost, when the app is also running inside Visual Studio Express for Win8 (where localhost is enabled).
.Kraig