I am using Castle Windsor as an IoC with my MVC website project. I have it initialised it by doing the following:
new CastleInitialiser(new WindsorContainer().Install(FromAssembly.InDirectory(new AssemblyFilter(HttpRuntime.BinDirectory, "ProjectName*.dll"))));
And then in my constructor I have the following that registers my controllers:
Container.Register(CastleClasses.FromThisAssembly().IncludeNonPublicTypes().BasedOn<Controller>().LifestylePerWebRequest());
This all works fine but now when I hit a url that doesn't exist, I don't get a 404 error thrown - I get the following error message:
The IControllerFactory 'ProjectName.Website.Castle.IoC.CastleControllerFactory' did not return a controller for the name 'asdasdasasdasd'.
Where asdasdasasdasd is the name of the invalid url
Is there any way to get this so that it throws a 404 exception instead of a castle windsor exception?
In my CastleController class, I am able to throw the 404 like so:
public class WindsorControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, "page not found");
}
return (IController)container.Resolve(controllerType);
}
}
Related
I am using Unity to do dependency injection in ASP.Net MVC by creating a custom controller activator class as,
public class CustomControllerActivator : IControllerActivator
{
public IController Create(RequestContext requestContext, Type controllerType)
{
var controller = default(IController);
if (controllerType != default(Type))
{
controller = ServiceLocator.Current.GetInstance(controllerType) as IController;
}
return controller;
}
}
and then a custom dependency controller resolver class as follows,
public class CustomControllerDependencyResolver : IDependencyResolver
{
public object GetService(Type serviceType)
{
var resolvedObject = default(object);
if (serviceType == typeof(IControllerActivator))
{
resolvedObject = new CustomControllerActivator();
}
return resolvedObject;
}
public IEnumerable<object> GetServices(Type serviceType)
{
var resolvedObjects = default(IEnumerable<Object>);
resolvedObjects = ServiceLocator.Current.GetInstances(serviceType);
return resolvedObjects;
}
}
then I add the following line to global.asax.cs file,
DependencyResolver.SetResolver(new CustomControllerDependencyResolver());
to register my custom dependency resolver.
The above method holds good for MVC controllers but when I used to do the same for webapi controllers it fails as ,
An error occurred when trying to create a controller of type 'CustomerController'. Make sure that the controller has a parameterless public constructor.
The problem is that the MVC and Webapi are working by their own DI so it creates object from the constructor of the controller which must be pram-less, but when you trying to make your own param constructor which will depend on your DI, you will need to install the configs which learn MVC or Webapi to handle your DI
in your case you are using Unity so you have to install unity.webapi
and this is the code :
PM> Install-Package Unity.WebAPI -Version 0.10.0
I have a simple controller :
public class UsersController : ApiController
{
[HttpPost]
[AllowAnonymous]
public HttpResponseMessage Login([FromBody] UserLogin userLogin)
{
var userId = UserCleaner.Login(userLogin.MasterEntity, userLogin.UserName, userLogin.Password, userLogin.Ua);
if (userId == null) return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "User not authorized");
return Request.CreateResponse(HttpStatusCode.OK, Functions.RequestSet(userId));
}
}
As you can see , only POST is currently available .
But when I invoke a GET in a browser (just for checking):
http://royipc.com:88/api/users
I get :
{"Message":"The requested resource does not support http method
'GET'."}
It is clear to me why it happens. But I want to return a custom exception when it happens.
Other answers here at SO doesn't show how I can treat this kind of situation (not that i've found of, anyway)
Question
How (and where) should I catch this kind of situation and return custom exception (HttpResponseMessage) ?
NB
I don't want to add a dummy GET method just for "catch and throw". tomorrow there can be a GET method. I just want to catch this Exception and return my OWN !
You may need to inherit from ApiControllerActionSelector class which is what the Web API uses to select the required action.
then you can replace the default IHttpActionSelector by your new action selector like that. config.Services.Replace(typeof(IHttpActionSelector), new MyActionSelector());
check this url for full example: http://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller/
You can build custom Exception filters in ASP.Net WebAPI. An exception filter is a class that implements the IExceptionFilter interface. To create a custom exception filter you can either implement the IExceptionFilter interface yourself or create a class that inherits from the inbuilt ExceptionFilterAttribute class. In the later approach all you need to do is override the OnException() method and plug-in some custom implementation.
public class MyExceptionFilter:ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An unhandled exception was thrown by the Web API controller."),
ReasonPhrase = "An unhandled exception was thrown by the Web API controller."
};
context.Response = msg;
}
}
you would likely want to test for conditions and generate the exact exception, but this is a bare example.
To use the exception class, you can either register it in the Global.asax, or as an attribute on a specific class or method.
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configuration.Filters.Add(new WebAPIExceptionsDemo.MyExceptionFilter());
AreaRegistration.RegisterAllAreas();
...
}
}
or
[MyExceptionFilter]
public class UsersController : ApiController
{
...
}
I am seeing an issue in using of unity in controller constructor. Here are the details -
In unit configuration (unity.config)– here is what I am doing –
container.RegisterType<ISessionWrapper, SessionWrapper>()
In the Controller constructor
public OnboardingController( ISessionWrapper sessionwrapper )
{
SessionWrapper = sessionwrapper;
}
SessionWrapper
public interface ISessionWrapper
{
string Brand { get; set; }
//string CurrenSessionCulture { get; set; }
}
public class SessionWrapper : ISessionWrapper
{
public string Brand
{
get;
set;
}
}
Error occuring in doing this
No parameterless constructor defined for this object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.****
When I change the Controller Constructor definition like this it is all working fine.
public OnboardingController()
: this(new SessionWrapper())
{
//
}
You need to use a custom ControllerFactory using Unity to resolve instances of your controller classes. The default ControllerFactory used by MVC requires that the controller classes have a parameterless constructor.
A custom ControllerFactory using Unity looks like
public class UnityControllerFactory : DefaultControllerFactory {
private readonly IUnityContainer _container;
public UnityControllerFactory (IUnityContainer container) {
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
if (controllerType != null) {
return _container.Resolve(controllerType) as IController;
}
else {
return base.GetControllerInstance(requestContext, controllerType);
}
}
}
On application start (normally in the global.asax) you register your ControllerFactory in the MVC Runtime using the following code
var container = // initialize your unity container
var factory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(factory);
I'm having troubles handling all types of errors in ASP.NET WebAPI.
I've successfully handled exceptions thrown inside my action methods using an ExceptionFilter and 404 errors for invalid routes, invalid controller or action name. However, I'm struggling to handle the error where the controller and action are both found, but the parameters for model binding are incorrect types.
Here's my action, which is routed to /api/users/{id}.
[HttpGet]
public virtual TPoco Get(long id)
{
...
}
If I request the URL /api/users/notinteger, I get a 400 Bad Request error that is handled outside of my code:
{
Message: "The request is invalid.",
MessageDetail: "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int64' for method '___ Get(Int64)' in '___'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
How can I intercept this error and respond with my own error message? Preferably not in the controller itself as I'd like to handle several controllers in the same way.
I've tried using global.asax.cs's Application_Error event as per this question, but that doesn't seem to be called in this case.
It appears that these errors are added to the ModelState as model binding errors. The action selector selects the correct action and the action invoker invokes it without throwing any errors.
The workaround I came up with is to create an action invoker that checks the ModelState for errors. If it finds any, it passes the first one to the exception handling method used by my ExceptionFilter and ErrorController.
internal class ThrowModelStateErrorsActionInvoker : ApiControllerActionInvoker
{
public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
foreach (var error in actionContext.ModelState.SelectMany(kvp => kvp.Value.Errors))
{
var exception = error.Exception ?? new ArgumentException(error.ErrorMessage);
//invoke global exception handling
}
return base.InvokeActionAsync(actionContext, cancellationToken);
}
}
It's nasty, but it works. This has taken up most of my day and I'm just glad to have finally got somewhere.
I'd be interested to know what the consequences are to this. What else uses the ModelState errors in Web API? Could anyone add some possible flaws in this solution?
It will more better if you use the new WebApi 2.1 Global error handling as discussed here,
http://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling&referringTitle=Specs
http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-21#global-error
If you are not willing to use WebApi 2.1 for a valid reason then you can try. (Note I have not tested but you can try). Create a custom action descriptor by inheriting with ReflectedHttpActionDescriptor and handle ExecuteAsync. This is what I mean,
public class HttpNotFoundActionDescriptor : ReflectedHttpActionDescriptor
{
ReflectedHttpActionDescriptor _descriptor;
public HttpNotFoundActionDescriptor(ReflectedHttpActionDescriptor descriptor)
{
_descriptor = descriptor;
}
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
{
try
{
return descriptor.ExecuteAsync(controllerContext, arguments, cancellationToken);
}
catch (HttpResponseException ex)
{
//..........................
}
}
}
public class HttpNotFoundAwareControllerActionSelector : ApiControllerActionSelector
{
public HttpNotFoundAwareControllerActionSelector()
{
}
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
HttpActionDescriptor decriptor = null;
try
{
decriptor = base.SelectAction(controllerContext);
}
catch (HttpResponseException ex)
{
var code = ex.Response.StatusCode;
if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed)
throw;
var routeData = controllerContext.RouteData;
routeData.Values["action"] = "Handle404";
IHttpController httpController = new ErrorController();
controllerContext.Controller = httpController;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
decriptor = base.SelectAction(controllerContext);
}
return new HttpNotFoundActionDescriptor(decriptor);
}
}
Note you need to override all the virtual methods.
I got an error on the creation of an api controller due to that I didn't set up autofac for webapi.
However, I can't seem to catch the exception anywhere.
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'MyWeb.Web.Controllers.MyController' does not have a default constructor
</ExceptionMessage>
<ExceptionType>System.ArgumentException</ExceptionType>
<StackTrace>
at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
</Error>
I tried adding WebApi contrib for Elmah, then I added this:
config.Filters.Add(new Elmah.Contrib.WebApi.ElmahHandleErrorApiAttribute());
Didn't make elmah register the exception.
I added the following to global.asax:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
}
Didn't make any difference at all.
How can I handle errors happening before the controllers are called?
I wonder if this exception is just being added to the content of the HttpResponseMessage but is not actually being thrown as an exception. When implementing a dependency resolver class for use during constructor instantiation, it usually makes sense to attempt resolution, catch exceptions and return null.
For example, in non-API MVC controllers I've often used something like this:
public class UnityDependencyResolver : IDependencyResolver
{
public readonly IUnityContainer Container;
public UnityDependencyResolver(IUnityContainer container)
{
Container = container;
}
#region IDependencyResolver Members
public object GetService(Type serviceType)
{
try
{
return Container.Resolve(serviceType);
}
catch (Exception ex)
{
if (ex.InnerException is TypeInitializationException)
throw ex.InnerException;
return null;
}
}
...