Как настроить приложение для нескольких арендаторов, используя ASP.NET MVC? - PullRequest
3 голосов
/ 29 ноября 2011

A приложение для нескольких арендаторов - это приложение, которое используется несколькими организациями (медицинскими учреждениями, адвокатскими конторами ...), и каждая организация, в свою очередь, имеет своих собственных пользователей. Все они входят в централизованную среду.

Чтобы быть идентифицированным в приложении, организация должна быть указана в URL. Для этого есть две основные формы URL. Субдомены и папки:

  • [tenancy_name].appname.com/projects/view/123
  • www.appname.com/[tenancy_name]/projects/view/123

Сначала я попробовал второе, потому что это решение не связано с работой с DNS. Но тогда проблема: каждый раз, когда разработчику нужно выразить URL (@Html.Action или @Url.Action), он должен явно передать [tenancy_name]. Это добавляет нежелательные накладные расходы на разработку. Возможный обходной путь может заключаться в реализации пользовательских версий этих помощников HTML, которые автоматически принимают во внимание имя арендатора. Я рассматриваю этот вариант, но ищу что-то более прямолинейное. Я также понял, что ASP.NET MVC автоматически передает значения маршрута для исходящих URL-адресов, но только когда контроллер и действие совпадают с текущим. Было бы хорошо, если бы значения маршрута всегда передавались.

Для реализации первого варианта, субдомена, я думаю, мне понадобится какой-нибудь сторонний диспетчер DNS. Я слышал о DynDNS и посмотрел на него, но мне показалось неясным, как они работают, просто глядя на их сайт. Нужно ли мне запускать веб-сервис, чтобы указывать им создавать новый поддомен каждый раз при создании нового клиента? Поддерживают ли они подстановочные знаки в DNS? Они работают на Windows Azure или общих хостингах?

Я здесь ищу направление. Куда мне идти?

Ответы [ 2 ]

1 голос
/ 03 декабря 2011

посмотрите этот проект на codeplex, возможно, "baseRoute" может вам помочь.

http://mvccoderouting.codeplex.com/

С уважением.

0 голосов
/ 29 августа 2014

После того, как в нашем приложении сделано тривиальное разрешение представления:

Как использовать: Для представлений, которые необходимо перегрузить для конкретного арендатора, обрабатывать их так же, как и в пользовательских режимах отображения: Следующее будет работать:

Index.cshtml
Index.cust2.mobile.cshtml

или

Partials/CustomerAgreement.cust1.cshtml
Partials/CustomerAgreement.cust2.cshtml

, насколько я помню, шаблоны отображения / редактора также работают одинаково

Известные проблемы: 1. Необходимо создать макеты для всех комбинаций основных+ вторичный (по любой MVC-причине) 2. Независимо от того, что Resharper говорит о своей поддержке режимов отображения - он не поддерживает "."как часть имени режима отображения (вот проблема для отслеживания прогресса http://youtrack.jetbrains.com/issue/RSRP-422413)

//put in application start --------

DisplayModeProvider.Instance.Modes.Clear();
foreach (var displayMode in GetDisplayModes())
{
    DisplayModeProvider.Instance.Modes.Add(displayMode);
}

private IEnumerable<IDisplayMode> GetDisplayModes()
{
    return new CompoundDisplayModeBuilder()
        .AddPrimaryFilter(_ => dependencyResolver.GetService(typeof(IResolveCustomerFromUrl)).GetName(),
            "cust1",
            "cust2")
        .AddSecondaryFilter(ctx => ctx.Request.Browser.IsMobileDevice, "mobile")
        .BuildDisplayModes();
}

//end of application start part


//and the mode builder implementation:
public class CompoundDisplayModeBuilder
{
    private readonly IList<DefaultDisplayMode> _primaryDisplayModes = new List<DefaultDisplayMode>();
    private readonly IList<DefaultDisplayMode> _secondaryDisplayModes = new List<DefaultDisplayMode>();

    //NOTE: this is just a helper method to make it easier to specify multiple tenants in 1 line in global asax
    //You can as well remove it and add all tenants one by one, especially if resolution delegates are different
    public CompoundDisplayModeBuilder AddPrimaryFilter(Func<HttpContextBase, string> contextEval, params string[] valuesAsSuffixes)
    {
        foreach (var suffix in valuesAsSuffixes)
        {
            var val = suffix;
            AddPrimaryFilter(ctx => string.Equals(contextEval(ctx), val, StringComparison.InvariantCultureIgnoreCase), val);
        }

        return this;
    }

    public CompoundDisplayModeBuilder AddPrimaryFilter(Func<HttpContextBase, bool> contextCondition, string suffix)
    {
        _primaryDisplayModes.Add(new DefaultDisplayMode(suffix) { ContextCondition = contextCondition });
        return this;
    }

    public CompoundDisplayModeBuilder AddSecondaryFilter(Func<HttpContextBase, bool> contextCondition, string suffix)
    {
        _secondaryDisplayModes.Add(new DefaultDisplayMode(suffix) { ContextCondition = contextCondition });
        return this;
    }

    public IEnumerable<IDisplayMode> BuildDisplayModes()
    {
        foreach (var primaryMode in _primaryDisplayModes)
        {
            var primaryCondition = primaryMode.ContextCondition;
            foreach (var secondaryMode in _secondaryDisplayModes)
            {
                var secondaryCondition = secondaryMode.ContextCondition;
                yield return new DefaultDisplayMode(primaryMode.DisplayModeId + "." + secondaryMode.DisplayModeId){
                    ContextCondition = ctx => primaryCondition(ctx) && secondaryCondition(ctx)
                };
            }
        }

        foreach (var primaryFilter in _primaryDisplayModes)
        {
            yield return primaryFilter;
        }

        foreach (var secondaryFilter in _secondaryDisplayModes)
        {
            yield return secondaryFilter;
        }

        yield return new DefaultDisplayMode();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...