2014-11-17 5 views
1

У меня есть сайт ASP.net MVC (5.2), который работает с использованием нескольких поддоменов, где имя поддомена - это имя клиента в моей базе данных. В основном то, что я хочу сделать, это использовать субдомен в качестве переменной в моих методах действий, чтобы я мог получить правильные данные из моей базы данных.Использование субдомена в качестве параметра

Я сделал что-то подобное несколько лет назад, но это грязно и неинтуитивно, поэтому было интересно, есть ли лучший способ сделать это, чем я использовал раньше. Вот что я делал раньше:

protected override void OnActionExecuting(ActionExecutingContext filterContext) { 
    Session["subdomain"] = GetSubDomain(Request.Url); 
} 

private static string GetSubDomain(Uri url) { 
    string host = url.Host; 
    if (host.Split('.').Length > 1) { 
     int index = host.IndexOf("."); 
     string subdomain = host.Substring(0, index); 
     if (subdomain != "www") { 
      return subdomain; 
     } 
    } 
    return null; 
} 

Которые в основном присваивается ключ к переменной сеанса, если поддомен было ничего, кроме «WWW», но я действительно не доволен этим способом сделать это, поскольку это зависит от мне известно, что сессия может содержать это волшебное значение!

В идеале я хотел бы создать атрибут, который я могу украсить своими классами/методами, чтобы извлечь субдомен, а затем разрешить включать параметр «поддомен» в мой метод действий, который будет содержать значение извлекается атрибутом. Возможно ли это?

Если это невозможно, есть ли лучший способ сделать то, что я сейчас делаю, не полагаясь на сеанс?

Спасибо,

Дилан

+0

Конечно, клиент будет необходимо войти в систему? Разве это не было бы легче загрузить в названии в этот момент? – James

+0

Я сразу понял, что могу создать приватную переменную в контроллере, а метод OnACtionExecuting записывает это вместо сеанса, но это все равно означает необходимость включать логику на каждую страницу, так что я все еще нахожусь после более чистый способ сделать это, что не заставляет меня повторять код. –

+0

Я думаю, что 'Session' является правильным местом для сохранения значения, однако, я думаю, что ваша идея вытащить его из URL * за запрос * неверна. Как я уже сказал, клиент должен войти в систему в какой-то точке, поэтому * должен быть ассоциацией с клиентом и именем - после успешного входа я просто установил бы имя в 'Session'. – James

ответ

0

Ваше право не нужно хранить в сеансе, а IMHO не должно быть, я бы реорганизовал это в свой класс и использовал HttpContext.Current.

public interface ISubDomainProvider 
{ 
    string SubDomain { get; set; } 
} 


public class SubDomainProvider : ISubDomainProvider 
{ 
    public SubDomainProvider() 
    { 
     string host = HttpContext.Current.Request.Url.Host; // not checked (off the top of my head 
     if (host.Split('.').Length > 1) 
     { 
      int index = host.IndexOf("."); 
      string subdomain = host.Substring(0, index); 
      if (subdomain != "www") 
      { 
       SubDomain = subdomain; 
      } 
     } 
    } 

    public string SubDomain { get; set; } 
} 

Вы выбираете, как использовать его, если вы используете контейнер IoC было бы просто случай впрыскивания этого класса в контроллер через конструктор, мне это нравится, потому что это гораздо легче высмеивать и Test Unit. Конечно, вы все еще можете это сделать:

public class SomeController : Controller 
{ 
    private readonly ISubDomainProvider _subDomainProvider; 
    public SomeController() 
    { 
     _subDomainProvider = new SubDomainProvider(); 
    } 
} 

Вы можете даже создать собственный абстрактный класс контроллера:

public abstract class MyAbstractController : Controller 
{ 
    public MyAbstractController() 
    { 
     SubDomain = new SubDomainProvider(); 
    } 

    protected string SubDomain {get; set; } 
} 

public class SomeController : MyAbstractController 
{ 
    public ActionResult SomeAction() 
    { 
     // access the subdomain by calling the base base.SubDomain 
    } 
} 
+0

Это выглядит как хороший способ сделать это, и кажется более гибким, чем использование атрибута. Благодаря! –

+0

@FooBar почему бы вам не почувствовать, что его нельзя хранить в сеансе? Он специфичен для пользователя, он должен быть доступен в течение всего сеанса и требуется только один раз (после начала сеанса). FYI, имеющий внешнюю зависимость, подобную «HttpContext», похороненную в вашем «SubDomainProvider», не самая лучшая идея. Лучшим подходом было бы иметь такой метод, как 'GetSubDomain (string url)' и передать URL-адрес запроса. – James

+0

@James Хороший вопрос! Я считаю, что это скорее конкретный запрос, а не специфический для пользователя. Он должен быть доступен только на время запроса, поэтому нет необходимости в том, чтобы он сохранялся между запросами, поскольку URL-адрес запроса доступен. Хранение сессии происходит с накладными расходами. Так зачем использовать, когда это не нужно? Сессия также сложнее Mock, чем интерфейс, когда дело доходит до Unit Tests. – SimonGates

0

Вы можете установить имя в Session на Session_Start событие в global.asax, это означает, что будет происходить только один раз, и будет сохраняться на период сессии пользователей

public void Session_Start(object sender, EventArgs e) 
{ 
    Session["subdomain"] = GetSubDomain(Request.Url); 
} 
+0

Это возможность. Если пользователь отправляется на client1.example.com, а затем посещает client2.example.com, это начало нового сеанса, не так ли? На самом деле маловероятно, что пользователь будет делать это из-за природы сайтов, но должен быть уверен в крайних случаях! –

+0

@ DylanParry Я так считаю, по крайней мере, если вы используете сеансы на основе файлов cookie (стоит проверить его, чтобы убедиться). – James

0

Похоже, что есть хороший способ сделать то, что я после того, как на сайте:

ASP.NET MVC Pass object from Custom Action Filter to Action

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

На стороне плюс это позволяет избежать использования сессии и опираясь на магических значениях объектов , но с другой стороны это означает обработку URL-адреса для каждого запроса, что, вероятно, не является хорошей идеей, если задействована база данных.

+0

Я не уверен, почему вы считаете, что «сессия» является неправильным решением здесь? Объект 'Session' был предназначен для * точно * этой цели - хранения данных, связанных с пользователем, на время посещения пользователей. Я бы понял, что выделение памяти было проблемой, но мы говорим о строке ... – James

+0

Это больше, потому что она полагается на меня * зная *, что в сеансе есть волшебное значение, которое было установлено где-то выше в коде, всегда чувствовал себя как хак для меня. Если кто-то другой возьмет на себя код, тогда это может быть не сразу очевидным, откуда это значение. –

+0

Я бы подумал, что немного не-вопрос сам, однако, если вы предпочитаете не использовать «сессию», но хотите избежать извлечения субдомена каждый раз, тогда я рекомендую [кэширование] (http://msdn.microsoft.com/en-us/library/6hbbsfk6(v=vs.100).aspx). Таким образом, вы сначала проверите кеш, и если его нет, извлеките его, если answser, с которым вы связались, - это подход, который вы собираетесь принять, я могу закрыть это как дубликат. – James

Смежные вопросы