I have a few http handlers (IHttpHandler) in my asp.net web project. Now I want to restrict access to these handlers. For Handler1 I want to allow only POST requests, and for Handler2 I want to allow only GET requests.
In my web.config I modified the <httpHandlers> section as shown below, but both handlers still process all verb types. Is there something I've missed? I'm testing it using IIS Express.
<httpHandlers>
<add verb="POST" path="Handler1.ashx" type="MyNamesapce.Handler1, MyAssembly"/>
<add verb="GET" path="Handler2.ashx" type="MyNamesapce.Handler2, MyAssembly"/>
</httpHandlers>
The reason this isn't working for you is that you've conflated two slightly different "flavours" of something that implements IHttpHandler.
There are two ways that you can implement an IHttpHandler with asp.net:
Create a class that implements IHttpHandler, e.g. MyCustomHandler.cs. This type of handler won't respond to any requests without being configured in your web.config file.
Create an .ashx file (which it looks like you've done), e.g. MyOtherHandler.ashx. This type of handler will respond to any requests to its URL, e.g. http://localhost/MyOtherHandler.ashx
The first type requires entries in the web.config file to work, the second doesn't. This is why you're seeing your .ashx handlers responding to all HTTP verbs, because they're being handled by the part of the asp.net framework that responds to requests for .ashx files, rather than being triggered by your web.config file. If you're using IIS Express, you can see this configured in the file %USERPROFILE%\Documents\IISExpress\config\applicationhost.config. Search for ".ashx" and you'll find a line similar to the below in the <system.webServer><handlers> section:
<add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx"
verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory"
preCondition="integratedMode,runtimeVersionv4.0" />
This is equivalent to what you've been adding to your web.config, but is responsible for telling IIS/asp.net "respond to any URLs that end in .ashx with any of the listed verbs by having the code in the type System.Web.UI.SimpleHandlerFactory deal with it. This code then loads your .ashx file.
To create a handler that can respond to any address you choose, you need (in short) a .cs file containing something similar to:
using System.Web;
namespace HttpHandlers
{
public class Handler4 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("Hello World from Handler4.cs");
}
}
}
You can then wire it into your web.config file with:
<add name="Handler4" verb="POST" path="Handler4.ashx" type="HttpHandlers.Handler4, HttpHandlers" />
NOTE: My project that I created to test this is called "HttpHandlers", hence the type declaration that I've specified in that web.config snippet.
Related
I have a C# MVC app with some React components.
Chrome works fine, but Edge is throwing a Origin https.... not found in Acces-Control-Allow-Origin Header
I've read pretty much everything related to CORS and MVC, but can't find a fix.
What i've tried so far ->
Web.Config
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
Custom CORS handler
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Headers", "*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Credentials", "true");
base.OnActionExecuting(filterContext);
}
[AllowCrossSite]
public class ReactController : Controller {....}
None of the above seem to be working. Edge still throws the CORS error (even tho' its about a resource on the same domain (perhaps related to npm packages or something).
Any tip?
Edit: Forgot to mention (perhaps it will help). This console.log does get triggered, but nothing beyond that point.
import * as React from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { DetailsList, DetailsListLayoutMode, Selection, buildColumns } from 'office-ui-fabric-react/lib/DetailsList';
import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection';
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
import { createRef } from 'office-ui-fabric-react/lib/Utilities';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
import { css, classNamesFunction } from 'office-ui-fabric-react/lib/Utilities';
import { DefaultButton, IButtonProps } from 'office-ui-fabric-react/lib/Button';
import { Label } from 'office-ui-fabric-react/lib/Label';
initializeIcons(/* optional base url */);
console.log("Initialized ");
UPDATE: I think i found out where my problem is (or another one related to the amazing EDGE).
The problem might be the fact that im loading a list that depends on a specific fetch request (im building a sharepoint provider hosted add-in). MS Edge seems to hate the OPTIONS Http Verb as it throws an error saying it is not supported....
Any idea on how i could fix this?
As i thought after a lot of wasted time the error was because of the fetch() that i was doing.
I installed axios and it seems that axios.get() works without any kind of error.
We have rolled out a classic ASP.Net WebService application with large traffic. Though our database is running quite well (<10 ms response times), most of the time spent in WebServer is in the MapRequestHandler stage.
The issue seems to be deep in the ASP .Net stack and without any information available on net, I am clueless as to how to go about improving it.
We use XML payloads for request/response (if that would help in providing a solution).
Please post you handler code and your config files.
MapRequestHandler - The MapRequestHandler event is used by the ASP.NET infrastructure to determine
request handler for the current request based on the file-name extension of the requested resource. MapRequestHandler is an event that the handlers need to implement, I suspect its stuck at some delegate that maps some custom file.
I suspect its 1) Not finding, looping around to find that custom file handler, you may not 2) using the async handler
You have to chase down the various delegate that use this event and setup a break point
Make sure they are Async & Registered for e.g.
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler" />
<add verb="*" path="*.asmx" type="System.Web.Services.Protocols.WebServiceHandlerFactory" />
Then under the handlers verify
<httpHandlers>
<add verb="*" path="*.MyCustomaspx" type="MyCustomHTTPhandler"/>
</httpHandlers>
In your implementation use the async version base handler
// dervie from Async HttpTaskAsyncHandler
public class MyCustomHTTPhandler: HttpTaskAsyncHandler {
public override Task ProcessRequestAsync(HttpContext context)
{
//throw new NotImplementedException();
//blah blah.. some code
}
}
Last resort, not recommended - from SO here, if your handler/page doesnt modify session variables, you can skip the session lock.
<% #Page EnableSessionState="ReadOnly" %>
If your page does not read any session variables, you can opt out of this lock entirely, for that page.
<% #Page EnableSessionState="False" %>
If none of your pages use session variables, just turn off session state in the web.config.
<sessionState mode="Off" />
Based on this if you want to customize session state just based on your specific page/handler
using System;
using System.Web;
public class CustomSessionStateModule : IHttpModule
{
public void Dispose(){ //.. }
public void Init(HttpApplication context){
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e){
HttpContext currentContext = (sender as HttpApplication).Context;
// here you can filter and turn off/on the session state
if (!currentContext.Request.Url.ToString().Contains("My Custom Handler or Page Value")){
// for e.g. change it to read only
currentContext.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.ReadOnly);
}
else {
//set it back to default
currentContext.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.Default);
}
}
}
I'm looking for a walkthrough on how to create and use a custom provider for ASP.Net Healthmonitoring.
So far I've only worked with the e-mail provider that generates e-mails on errors. Basically I want to do the same, but with more flexibility:
I want to use the HealthMonitoring features (I don't want to use the Application_OnError event in the global.asax) in a way that allows me have access to an event, that gets thrown like "OnNewHealthMonitoringEntry" with all the information provided in the e-mail, to run custom code.
Edit:
Based on the source code provided here http://www.asp.net/general/videos/how-do-i-create-a-custom-provider-for-logging-health-monitoring-events I was able to build my own custom provider and implement it. Now I want to add some new attributes to configure my custom provider.
Here is what the web.config looks like:
<healthMonitoring>
<bufferModes>
<add name="Log Notification" maxBufferSize="1" maxFlushSize="1" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:00:10"/>
</bufferModes>
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
<profiles>
<add name="Custom" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"/>
</profiles>
<rules>
<add name="File Event Provider" eventName="All Errors" provider="FileEventProvider" profile="Custom"/>
</rules>
</healthMonitoring>
If I attempt to add an attribute to the provider, like this
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" foo="bar" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
I'll get an error saying:
An exception of type
'System.Configuration.ConfigurationErrorsException'
occurred in System.Web.dll but was not
handled in user code Additional
information: Unexpected attribute foo
in the configuration of the
FileEventProvider.
Is it possible to store configuration necessary for custom provider close to the healthMonitoring section? I guess I could include the settings into the appSettings node, but I'd like to configure it somehow with attributes (inside the healthMonitoring node). Is that possible?
Edit2:
You might take a look at this article: http://www.tomot.de/en-us/article/6/asp.net/how-to-create-a-custom-healthmonitoring-provider-that-sends-e-mails
The following series of articles will take you through the basics of using the Health Monitoring System upto creating Custom Events.
Then the following 26 minute video will take you through creating a custom provider that records events to a text-based log file.
UPDATE Based on Comment
Looking at your update and using Reflector to look at the source for the BufferedWebEventProvider class that you base your custom provider on, I have found that the Initialize method in BufferedWebEventProvider does a check at the end to see if there are any attributes that it doesn't recognize. This is done by removing values from the config NameValueCollection parameter as soon as they are assigned to the properties or fields of the BufferedWebEventProvider. Then a check is done to see if the config parameter is empty and if not that means that there are extra attributes added, which causes an exception to be thrown.
As to how to fix this problem, one option is to:
Move the call to base.Initialize to the end of the method
Remove the additional attributes as soon as you assign them to variables just like the provider does.
Something like the following would work:
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
foo = config["foo"];
if (String.IsNullOrEmpty(foo))
{
// You can set a default value for foo
}
//remove foo from the config just like BufferedWebEventProvider with the other
//attributes. Note that it doesn't matter if someone didn't proivde a foo attribute
//because the NameValueCollection remains unchanged if you call its Remove method
//and the name doesn't exist.
config.Remove("foo");
base.Initialize(name, config);
}
Hopefully this works out for you.
I'm trying create a ASMX webservice that can perform a HTTP GET request. I have the following simple snippet of code to illustrate what I've already done.
using System.Web.Script.Services;
...
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HelloWorld(HttpContext context)
{
return context.Request.Params.Get("userId").ToString();
}
In addition to this, I've also added the following nodes in my Web.config file
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
The problem that I'm facing is that I'm constantly getting the dreaded "System.Web.HttpContext cannot be serialized because it does not have a parameterless constructor" error message whenever I try to debug this webservice. I have no idea what the problem is, and I would really appreciate any assistance that is offered to get me out of this quandary. I realize that HTTP GET requests are supposed to be very simple, but I'm really uncertain of what the cause of my frustrations are.
I think you want
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HelloWorld(int userId)
{
return userId.ToString();
}
You can specify parameters in the function signature and you can access the HttpContext as Context (a property on the base class WebService) if you need it.
I would like to make a RESTful app of HTTPhandlers without having to define every endpoint by making an entry in the web.config, i'd like the style of attaching attributes to a class constructor eg:
public class obj : IHttpHandler
{
[WebGet(UriTemplate = "/accounts/{id}")]
public obj(string id)
{
// this is just an eg, it worild normally include caching and
// a template system
String html = File.ReadAllText("/accounts/accounts.htm");
html.replace("id", id);
httpcontext.current.response.write(html)
}
}
instead of
<httpHandlers>
<clear />
<add verb="GET" path="/accounts/*" type="MyApp.obj" />
</httphandlers>
The way i'm doing it now i have 100's of endpoints in the web.config :( i'd rather define them in the class. And i don't want to make extra files (.asmx) either. I'd like an app of just .htm files with tokens and .cs files
Thanks!
You could automate the registration of the endpoints and so on, with a custom ServiceHost, which overrides the ApplyConfiguration() method, which then virtualizes the configuration so that it does not have to be in the web.config file.
Here's a starting point. It doesn't do exactly what you want, but it illustrates the concept of virtualizing the configuration.