Reputation: 2221
I have an abstract class called LanguageBase.
I have also have a derived class called Language (do not worry about WHY I do this - there is a valid use case for this but falls outside the scope of this discussion).
In my ASP.Net MVC application, I have a controller for which some of the action methods take LanguageBase as a parameter. During runtime, Autofac must resolve this to Language.
In Global.asax, I have the following method to register my types and create my container:
private void RegisterTypes()
{
var builder = new ContainerBuilder();
//http://autofac.readthedocs.org/en/latest/integration/mvc.html
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
builder.RegisterType<Language>().As<LanguageBase>();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
However, during runtime, I receive this error:
Server Error in '/' Application.
Cannot create an abstract class.
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: Cannot create an abstract class.
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.
Stack Trace:
[MissingMethodException: Cannot create an abstract class.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +113
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +206 System.Activator.CreateInstance(Type type, Boolean nonPublic) +83 System.Activator.CreateInstance(Type type) +11 System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +197[MissingMethodException: Cannot create an abstract class. Object type 'Visia.PartyRoles.Generic.IDomain.LanguageBase'.]
System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +233 System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +531
System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +330
System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +331
System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +105
System.Web.Mvc.Async.<>c__DisplayClass21.b__19(AsyncCallback asyncCallback, Object asyncState) +743
System.Web.Mvc.Async.WrappedAsyncResult1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +14
1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +343
System.Web.Mvc.Controller.b__1c(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +25
System.Web.Mvc.Async.WrappedAsyncVoid1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +465
System.Web.Mvc.Controller.b__14(AsyncCallback asyncCallback, Object callbackState, Controller controller) +18
System.Web.Mvc.Async.WrappedAsyncVoid1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +20
1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +374
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +16
System.Web.Mvc.MvcHandler.b__4(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +52 System.Web.Mvc.Async.WrappedAsyncVoid1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +30
1.Begin(AsyncCallback callback, Object state, Int32 timeout) +128
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +384
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +48
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +103 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
Am I missing something?
UPDATE
Here is my controller code...
using System;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Visia.MasterData.Banking.DAL;
using Visia.PartyRoles.Core.Banking.IDataServices;
using Visia.PartyRoles.Generic.IDomain;
namespace Visia.CrediScan.UI.Views
{
public class LanguagesController : Controller
{
private readonly QueryBase _query;
private readonly CommandBase _command;
public LanguagesController(QueryBase query, CommandBase command)
{
if (query == null) throw new ArgumentNullException(nameof(query));
if (command == null) throw new ArgumentNullException(nameof(command));
_query = query;
_command = command;
}
// GET: /Languages/Edit/5
public ActionResult Edit(long? id, long CountryId)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var language = _query.GetLanguage((long)id);
if (language == null)
{
return HttpNotFound();
}
ViewBag.CountryId = CountryId;
return View(language);
}
// POST: /Languages/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(LanguageBase language, long CountryId)
{
if (ModelState.IsValid)
{
language.CountryId = CountryId.ToString();
_command.Update(language);
return RedirectToAction("Index", new { CountryId = CountryId });
}
return View(language);
}
}
}
Upvotes: 0
Views: 1075
Reputation: 27861
You issue is not related to Autofac. It is the MVC framework that is responsible for creating the arguments for the action method based on the data from the request.
Although you can create a custom Model Binder (via the IModelBinder
interface) to solve your issue, I recommend that you don't have action parameters that contain behavior.
Instead, create a simple model (e.g. Language
) that contains only data and use it as an action parameter. And have another service (e.g. ILanguageService
) that contains that behavior that you might want to vary using DI. Such service would be injected into the constructor of the controller.
Take a look at this article. The way I see it, the action methods are at the boundary of your application. So your action parameters shouldn't be Object Oriented, i.e., they shouldn't contain behavior. They should be simple data objects. Then you can use another service to translate the simple data object to some object that is Object Oriented (contains behavior). Such service would then be injected through the constructor (and thus Autofac can handle it).
Upvotes: 2