Owin Middleware - owin

I have written a custom owin middleware for two factor authentication, but sometimes it happens HttpContext.Current.Session throws an exception of object reference is not set to an instance of an object, when it checks for new session.
I checked HttpContext.Current is null, it always works on Chrome, sometimes in IE, but not on Mozilla

You can refer the following link-http://vegetarianprogrammer.blogspot.in/2012/12/understanding-synchronizationcontext-in.html
You can add the following key in your config.
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
After investigation I found the solution, so that context wouldn't be null.
This will not make the context null when using async method.

Related

Error 405 - Method not allowed with IIS Express 10 with CORS for Web API

I know this question has been asked plenty of times, each with similar answers, but after hours on this problem, I've yet to get it resolved, so I'm hoping additional suggestions may be provided.
I'm getting Error 405 - Method not allowed
I've removed the WebDAV entries from the module and handler section as suggested.
I've also changed the ExtensionlessUrlHandler-Integrated-4.0. Removed it first as suggested but didn't work so re-added it but with a slightly different definition <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
verb="GET,POST,OPTIONS,PUT,DELETE"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
where each verb is defined rather than using *
I've ensure CORS was enabled i.e. app.UseCors(CorsOptions.AllowAll); is called from my Startup class in public void Configuration(IAppBuilder app)
Access-Control-Allow-Methods has been set in my web.config
The weird thing is that it works just fine for DELETE but not for PUT.
Here's my System.WebServer section from my web.config:
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/>
</modules>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods"
value="GET,POST,OPTIONS,PUT,DELETE" />
</customHeaders>
</httpProtocol>
<handlers>
<clear/>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
verb="GET,POST,OPTIONS,PUT,DELETE"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
When I run Fiddler, I'm getting the following:
HTTP/1.1 405 Method Not Allowed
Allow: GET,POST
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
X-SourceFiles: =?UTF-8?B?RDpcU3BpbmRldlxXb3JrXEpvaWZmTGlzdGluZ05lnM=?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,OPTIONS,PUT,DELETE
Date: Mon, 15 Jul 2019 23:41:32 GMT
Content-Length: 79
{
"message": "The requested resource does not support http method 'PUT'."
}
As you can see, the Access-Control-Allow-Origin and Access-Control-Allow-Methods appears to be set correctly but the Allow: is still set to GET,POST. Why is that? Where am I suppose to change this to have all the verbs?
And finally my action in my web controller is defined as follows:
[HttpPut]
[Route("id:{Guid}")]
public async Task<IHttpActionResult> UpdateCompany(Guid id)
{
}
Pretty standard stuff!
Any ideas and/or suggestions? Remember that I'm concentrating on getting this to work on IIS Express. Once I've got that resolved, I'll check it out in IIS but I really want to get to the bottom of this first.
Any help much appreciated.
Thanks.
UPDATE-1
I've just found an article from Microsoft regarding CORS, and even thought I'm enabling it as mentioned above, I've noticed that I don't have any references in my list of references to Microsoft.AspNet.WebApi.Cors which is odd and when I try to add the [EnableCors...] attribute, no references are shown which would indicate even more clearly that it may not be installed properly or at all.
I'll check that tomorrow and update.
I've also forgot to mention that OWIN is installed and set up. In the event this may give more clues as to why I still can't resolve this problem.
UPDATE-2
My add company (POST) is defined as follows:
[HttpPost]
public async Task<IHttpActionResult> AddCompany (
CompanyRequestDto companyRequestDto)
{
}
My update company (PUT) is defined as follows:
[HttpPut]
public async Task<IHttpActionResult> UpdateCompany (
Guid Id,
CompanyRequestDto companyRequestDto)
{
}
and my WebApiConfig.cs has the following route defined in it:
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I've removed [Route("id:{Guid}")] as I thought it could have been that, but it's not. Same issue.
As Andrei Dragotoniu suggested, commenting out my UpdateCompany function generated the very same error which means another function is being hit but I have no idea which one as none of the breakpoints I've put are being hit, nor, any of them are defined as PUT so it's confusion. I'm sure we'll get to the bottom of it.
UPDATE-3
I feel really stupid right now!! After wasting so much time researching this problem, it actually wasn't there! Unlike a POST request where you only post the object, the PUT request expected a CompanyId as part of the query string which I had omitted and cause the problem!
http://localhost:12345/Companies
instead of
http://localhost:12345/Companies/61770BAA-78A6-E911-AEB1-001A7DDA7111
Anyway, I'm glad I'm up and running and I hope nobody else will do something as silly as this but if you do, hopefully, this will help!
Do not do this on IIS Express, that's pointless. Get it working in proper IIS instead.
One thing to check, the error method tells you that the particular method you're accessing does not support PUT. This doesn't mean that the PUT verb is not enabled in config. What it means is that the particular method you're accessing does not support it.
You need to check and see which endpoint is being hit because it doesn't seem to be the one you think. Check your rules basically. Remember they get applied in order so you really want your most concrete ones to be loaded first and the most general one at the end.
One quick way to check this is to comment out the UpdateCompany(Guid id) endpoint and see if you still get the same response when you repeat the call in Postman. If you do, then it's obvious that your request is being handled by a different endpoint, not the one you think.

ELMAH - Get SMTP credentials from Azure Application Settings

I've got an Azure Web App using ELMAH to log unhandled exceptions.
When I first deployed it, the web.config had the full SMTP setup defined in it, and ELMAH emailed exceptions:
<system.net>
<mailSettings>
<smtp from="me#mydomain.com">
<network host="smtp.mailprovider.com"
port="123"
userName="myUserName"
password="p#ssw0rd" />
</stmp>
</mailSettings>
</system.net>
The username and password have since been removed from the web.config, and they're now stored as application settings, configured through the Azure Portal.
Most of the emails I send still work fine, as the email code can access these application settings and use them when instantiating the SmtpClient, e.g.:
var userName = WebConfigurationManager.AppSettings["smtp.userName"];
var password = WebConfigurationManager.AppSettings["smtp.password"];
var credentials = new NetworkCredential(userName, password);
using (var smtpClient = new SmtpClient { Credentials = credentials })
{
await smtpClient.SendMailAsync(mailMessage);
}
What's the best way to get ELMAH to use the credentials stored in the application settings?
Options I can see:
There is a page on the wiki explaining how to use ELMAH's ErrorTweetModule to do an HTTP form post with the error details to any URL. The controller receiving the post could then use the stored credentials to email the details on.
The WebBase has a link to an article suggesting you can send emails directly to the recipient's SMTP server without authentication, but it says this may not work if you have DomainKeys set up, which I do.
This answer links to an article about intercepting the Mailing event, to customise the message.
I ended up creating a custom version of Elmah's ErrorMailModule, derived from the standard one, but overriding the SendMail method, based on some advice from Atif Aziz in a discussion on Google Groups.
The only changes required were to create the new module, and switch the Web.Config to use the custom module instead of the standard one.
Module
using System;
using System.Net.Mail;
namespace Test
{
public class ErrorMailModule : Elmah.ErrorMailModule
{
protected override void SendMail(MailMessage mail)
{
if (mail == null) throw new ArgumentNullException(nameof(mail));
// do what you want with the mail
// (in my case this fires up the email service, which
// gets the credentials from the Azure settings)
}
}
}
Web Config Changes
All that's required is to change the two occurrences of Elmah.ErrorLogModule, Elmah to your own module, in this case Test.ErrorMailModule.
So, instead of this...
<system.web>
<httpModules>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
</modules>
</system.webServer>
...you should now have this:
<system.web>
<httpModules>
<add name="ErrorMail" type="Test.ErrorMailModule" />
</httpModules>
</system.web>
<system.webServer>
<modules>
<add name="ErrorMail" type="Test.ErrorMailModule" preCondition="managedHandler" />
</modules>
</system.webServer>
You will still need the errorMail section, as Elmah is still responsible for creating the email. Mine looks like this:
<elmah>
<errorMail from="user#domain.com" to="user#domain.com" subject="Custom Email Module"/>
</elmah>
Creating a HTTP request could work, but that should be the solution if everything else doesn't work IMO. Intercepting the Mailing event doesn't work, since you do not have access to the SmtpClient with the credentials in that event.
I've looked at different ways to update the SMTP settings from code. At first I though that I could just get a reference to the smtp section and update the properties, since they all have setter. But the code throw a configuration exception on runtime.
From what I can find, the only way to update the username and password in smtp section, is to read the web.config, update it and write the new version. Here's an example of writing updates to web.config:
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
var section = configuration.GetSection("system.net/mailSettings/smtp") as SmtpSection;
section.Network.UserName = ConfigurationManager.AppSettings["myusername"];
section.Network.Password = ConfigurationManager.AppSettings["mypassword"];
configuration.Save();
The code actually updates the web.config. The code can be run at startup, but that would modify your web.config file locally as well. Another approach would be to run the code as part of a post deployment task with Azure.

CORS problems in WebAPI hosted in IIS

I'm trying to implement an application that uses the same Token Based Authentication mechanism demonstrated in this really awesome example by Taiseer Joudeh.
In my application I kept encountering Cors problems. In some configurations I would get a 500 error on the Preflight (OPTIONS) request for the POST to get the token or I could get the token but then get a 404 error on the preflight request for the GET request to the actual API call with the Bearer token.
One difference was that Taiseer's code was setup to host in IISExpress (or Azure) and mine is hosted on Local IIS (running on Windows 7 at the moment).
On a hunch I tried hosting his API under Local IIS and I found the exact same problem. (500 error on the preflight request for the token and it looks like the actual API will work properly)
From what I've been reading it seems like this may be some conflict between the modules and handlers in IIS and the Cors implementation in WebApi but Taiseer's implementation works when hosted in Azure so perhaps it is a difference in the version of IIS (I'm currently running under Windows 7).
How can I sort out what is causing the problem?
The root of the problem
The Token action is not hosted in a controller but is instead built in somewhere in the lower level plumbing. The only access to the mechanism is through the override method GrantResourceOwnerCredentials() in the class that extends OAuthAuthorizationServerProvider. (In our case is ApplicationOAuthProvider.cs).
GrantResourceOwnerCredentials() does have the context available but it is not called as part of the PreFlight request so you have no way to insert the appropriate PreFlight response headers for CORS.
The solution
We eventually settled on the following solution. I'm not a big fan of it because it forces these headers into every response but at least it works.
The solution was to override Application_PreSendRequestHeaders() method in Global.asax to insert the appropriate headers.
Global.asax.cs
void Application_PreSendRequestHeaders(Object sender, EventArgs e)
{
var origin = Request.Headers.Get("Origin");
var validOrigins = ConfigurationManager.AppSettings["allowedCorsOrigins"].Split(',');
if(validOrigins.Any(o => o == origin))
{
Response.Headers.Set("Access-Control-Allow-Origin", origin);
Response.Headers.Set("Access-Control-Allow-Credentials", "true");
Response.Headers.Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, withcredentials, Prefer");
Response.Headers.Set("Access-Control-Expose-Headers", "Claims, *");
Response.Headers.Set("Access-Control-Max-Age", "600");
Response.Headers.Set("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
}
}
This requires the following web.config entries:
web.config
<configuration>
<appSettings>
<add key="allowedCorsOrigins" value="http://www.allowedsite1.net,http://localhost:22687" />
<add key="allowedCorsMethods" value="get, post, put, delete, options, batch" />
<add key="allowedCorsHeaders" value="*" />
</appSettings>
...
</configuration>
The reason for the loop to search for the valid origins is that you can't respond with a list of allowed origins...
This solved most of the problems with one exception (If I recall correctly was problems with PUT and DELETE verbs). This required removing the "ExtensionlessUrlHandler-Integrated-4.0" and re-adding it with a path and verb in the handlers section of the web.config.
web.config (2nd change)
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="" />
</handlers>
....
</system.webServer>
Useful links related CORS
Really good description of PreFlight for CORS
Excellent Sample Application using Token Auth
It is not the IdentityServer you are using but it could be the same problem. Regarding to the IdentityServer´s Github page you have to activate RAMMFAR (runAllManagedModulesForAllRequests) for your application when running under the IIS.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
I had this same issue, I did everythin as suggested by Mr. Tom hall. But still chrome reported no Access-control-allow-origin header is present.. after inspecting with fidler i realized that my request goes through a proxy server and my proxy server is handling the preflight options request..
So in "internet options" i removed the proxy server and found out that everything is working...!!!

MVC 5 Remote Validator - call web service

I built a remote validator (controller -> action) and decorated the field with the Remote attribute that points to the action and controller.
The action itself will take the value entered by user and call a remote service. The service will return true or false.
If the response is false then the remote validation returns false and the error message is shown.
The problem is that it works fine except that the input is not validated after the focus is lost on the field but after the form is submitted. Basically the form is submitted, hit's the controller action but the validation of the value occurs after submit and then the error message is shown.
Make sure your web.config has this set
<add key="ClientValidationEnabled" value="true" />
And for a cleaner output, you may also want to try enabling the unobtrusive validation as well.
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Just make sure your project has those javascript files included, they should have been added via Nuget

IIS applicationHost 'setEnvironment' attribute

<add name="ASP.NET v4.0" autoStart="true" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated">
<processModel identityType="ApplicationPoolIdentity" loadUserProfile="true" setProfileEnvironment="true" />
</add>
I'm adding that in appliationHost config of IIS to solve localDb problem in IIS what I see in this article
http://blogs.msdn.com/b/sqlexpress/archive/2011/12/09/using-localdb-with-full-iis-part-1-user-profile.aspx
Can you guys help me to avoid this error?
Unrecognized attribute 'setProfileEnvironment'
It looks like you are attempting to place the value inside of an actual application pool. That attribute lives outside of a defined application pool, and lives in appicationpooldefaults.
<applicationPoolDefaults>
<processModel identityType="ApplicationPoolIdentity" loadUserProfile="true" setProfileEnvironment="true" />
<applicationPoolDefaults>
Quick search for the error you provided points to outdated or broken IIS (the assembly that implements setProfileEnvironment attribute, or one of its dependencies, is either missing or broken). At least that's best guess based on the data provided.

Resources