преобразователь зависимостей asp.net mvc 4 для контроллеров

Я использую asp.net mvc 4 для разработки многопользовательского приложения mvc.

Я использую Autofac для контейнера IOC и настроил контроллеры для регистрации для каждого клиента в разных сборках.

Autofac переключит контроллер, который он возвращает, когда его попросят разрешить, в зависимости от текущего контекста клиента, который определяется путем просмотра данных маршрута.

я получаю исключение

Было найдено несколько типов, соответствующих контроллеру с именем «Дом».

Казалось бы, это указывает на то, что Autofac возвращает более одного совпадения, однако при ближайшем рассмотрении кажется, что MVC даже не вызывает Autofac для разрешения контроллера.

Я вижу вызов, который запрашивает IControllerFactory от DependencyResolver, но никогда не запрашивает сам контроллер.

Нужно ли мне реализовывать собственную фабрику контроллеров поверх использования преобразователя зависимостей?

Я просмотрел исходный код mvc и из того, что я могу сказать, DefaultControllerFactory использует разрешение зависимостей и должен разрешать контроллеры, но у меня возникли проблемы с отладкой, чтобы точно увидеть, что происходит.

На DLL-файлы арендатора не ссылается основной веб-сайт, но они копируются после сборки.

Мой global.asax выглядит следующим образом: // Во-первых, создайте параметры по умолчанию на уровне приложения с помощью стандартного // ContainerBuilder, как вы привыкли. var builder = новый ContainerBuilder(); var appContainer = builder.Build();

// Once you've built the application-level default container, you
// need to create a tenant identification strategy. The details of this
// are discussed later on.
var tenantIdentifier = new RouteDataTenantIdentificationStrategy();

// Now create the multitenant container using the application
// container and the tenant identification strategy.
var mtc = new MultitenantContainer(tenantIdentifier, appContainer);

// Configure the overrides for each tenant by passing in the tenant ID
// and a lambda that takes a ContainerBuilder.

var assemblies = AppDomain.CurrentDomain.GetAssemblies()
    .AsQueryable()
    .Where(a => a.IsDefined(typeof (PluginAssemblyAttribute), false));


foreach (var assembly in assemblies)
{
    var pluginSpecification =
        assembly.GetCustomAttributes(typeof(PluginAssemblyAttribute), false)
            .OfType<PluginAssemblyAttribute>()
            .Single();
    var assembly1 = assembly;
    mtc.ConfigureTenant(pluginSpecification.Tenant, 
        b => b.RegisterControllers(assembly1));
}

DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));

Стратегия идентификации арендатора выглядит следующим образом:

public class RouteDataTenantIdentificationStrategy 
    : ITenantIdentificationStrategy
{
    public bool TryIdentifyTenant(out object tenantId)
    {
        tenantId = null;
        var context = HttpContext.Current;
        try
        {
            if (context == null || context.Request == null)
            {
                return false;
            }
        }
        catch (HttpException)
        {
            // This will happen at application startup in MVC3
            // integration since the ILifetimeScopeProvider tries
            // to be resolved from the container at the point where
            // a new AutofacDependencyResolver is created.
            tenantId = null;
            return false;
        }

        var routeData = RouteTable.Routes.GetRouteData(
            new HttpContextWrapper(context));

        if (routeData != null)
            tenantId = routeData.Values.ContainsKey("tenant") ? 
                routeData.Values["tenant"] : null;

        return tenantId != null;
    }
}

РЕДАКТИРОВАТЬ: полное исключение

The request for 'Home' has found the following matching controllers:
MultiTenantViewEngine.Web.Controllers.HomeController
MultiTenantViewEngine.Web.Tenant1.Controllers.HomeController]
   System.Web.Mvc.DefaultControllerFactory.GetControllerTypeWithinNamespaces(RouteBase route, String controllerName, HashSet`1 namespaces) +230
   System.Web.Mvc.DefaultControllerFactory.GetControllerType(RequestContext requestContext, String controllerName) +833
   System.Web.Mvc.DefaultControllerFactory.System.Web.Mvc.IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, String controllerName) +196
   System.Web.Mvc.MvcRouteHandler.GetSessionStateBehavior(RequestContext requestContext) +267
   System.Web.Mvc.MvcRouteHandler.GetHttpHandler(RequestContext requestContext) +61
   System.Web.Mvc.MvcRouteHandler.System.Web.Routing.IRouteHandler.GetHttpHandler(RequestContext requestContext) +44
   System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +352
   System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +144
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +239
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +114

При более глубоком рассмотрении может показаться, что эта ошибка возникает из-за того, что GetControllerTypeWithinNamespaces() возвращает более одного пространства имен.

Есть ли способ преодолеть это?


person Daniel Powell    schedule 18.02.2013    source источник
comment
Как выглядит ваша RouteDataTenantIdentificationStrategy, и поставили ли вы в нее точку останова, чтобы увидеть, вызывается ли она при разрешении контроллера?   -  person Simon C    schedule 18.02.2013
comment
только что добавил его, дважды проверит, вызывается ли он   -  person Daniel Powell    schedule 18.02.2013
comment
кажется, что он вызывается и возвращает правильный tenantid   -  person Daniel Powell    schedule 18.02.2013
comment
Если вы еще этого не сделали, вы должны проверить статью Зака ​​Оуэнса об этом. weblogs.asp. сеть/zowens/архив/2010/05/26/   -  person unforgiven1987    schedule 14.03.2013
comment
Да, я видел, что, вероятно, это маршрут, по которому я в конечном итоге спущусь.   -  person Daniel Powell    schedule 15.03.2013


Ответы (1)


Вы должны указать пространство имен во всех ваших маршрутах:

routes.MapRoute(
"Default",                                              // Route name
    "{controller}/{action}/{id}",                           // URL with parameters
    new { controller = "Home", action = "Index", id = "" },  // Parameter defaults
    "Some.NameSpace.To.Controllers" // required
);

Если вы хотите использовать домашний контроллер в тенантной DLL: либо перенаправьте на него с основного сайта HomeController, либо создайте свой собственный маршрут (наследуется от Route) и сделайте в нем выбор пространства имен.

person jgauffin    schedule 18.02.2013
comment
Ну, в зависимости от контекста приложения, я либо хочу использовать контроллер в dll основного сайта, либо в dll tenant1, либо в dll другого арендатора, исходя из этого, может быть лучше написать свою собственную фабрику контроллеров, которая просто запрашивает преобразователь зависимостей подскажите типы? - person Daniel Powell; 18.02.2013
comment
Я бы предпочел использовать собственный маршрут, поскольку именно маршруты решают, какой контроллер загружать. ControllerFactory — это именно то, что есть: фабрика, создающая заказанный ею контроллер. - person jgauffin; 18.02.2013
comment
и я могу динамически переопределить пространство имен для поиска пользовательского маршрута? - person Daniel Powell; 18.02.2013