Custom IIdentity и передача данных из атрибута в контроллер
Вот мой сценарий:
Я успешно создал собственный IIdentity, который передаю GenericPrincipal. Когда я получаю доступ к этому IIdentity в моем контроллере, мне нужно наложить IIdentity, чтобы использовать пользовательские свойства. пример:
public ActionResult Test()
{
MyCustomIdentity identity = (MyCustomIdentity)User.Identity;
int userID = identity.UserID;
...etc...
}
Поскольку мне нужно выполнять это приведение почти для каждого действия, я хотел бы обернуть эту функциональность в атрибут ActionFilterAttribute. Я не могу сделать это в конструкторе контроллера, потому что контекст еще не инициализирован. Я бы хотел, чтобы ActionFilterAttribute заполнял частное свойство на контроллере, которое я могу использовать в каждом методе действия. пример:
public class TestController : Controller
{
private MyCustomIdentity identity;
[CastCustomIdentity]
public ActionResult()
{
int userID = identity.UserID;
...etc...
}
}
Вопрос: возможно ли это и как? Есть ли лучшее решение? Я пытался понять, как передать общедоступные свойства, которые заполнены атрибутом, в контроллер, и я не могу его получить.
2 ответа
Все, что вам нужно сделать, это получить доступ к ActionExecutingContext перегруженного метода OnActionExecuting() и сделать личность общедоступной, а не частной, чтобы ваш actionfilter мог получить к ней доступ.
public class CastCustomIdentity : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
((TestController) filterContext.Controller).Identity = (MyCustomIdentity)filterContext.HttpContext.User;
base.OnActionExecuting(filterContext);
}
}
Это может быть еще проще, если использовать пользовательский базовый класс контроллеров, от которого наследуются все ваши контроллеры:
public class MyCustomController
{
protected MyCustomIdentity Identity { get{ return (MyCustomIdentity)User.Identity; } }
}
а потом:
public class TestController : MyCustomController
{
public ActionResult()
{
int userID = Identity.UserId
...etc...
}
}
Вы можете использовать пользовательскую модель переплета...
Я не могу вспомнить, почему я использовал этот метод поверх метода базового контроллера, о котором упоминает @jfar (что также является хорошим вариантом), но он хорошо работает для меня, и мне действительно это нравится, потому что мои действия более самоопределяются через их параметры.
MyCustomIdentityModelBinder.cs
public class MyCustomIdentityModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.Model != null)
throw new InvalidOperationException("Cannot update instances");
//If the user isn't logged in, return null
if (!controllerContext.HttpContext.User.Identity.IsAuthenticated)
return null;
return controllerContext.HttpContext.User as MyCustomIdentity;
}
}
Внутри вашего приложения запускается событие в Global.asax.cs
System.Web.Mvc.ModelBinders.Binders.Add(typeof(MyCustomIdentity), new MyCustomIdentityModelBinder());
Тогда всякий раз, когда у вас есть тип MyCustomIdentity
в качестве параметра действия он будет автоматически использовать MyCustomIdentityModelBinder
,
Например.
public class TestController : Controller
{
public ActionResult Index(MyCustomIdentity identity)
{
int userID = identity.UserID;
...etc...
}
}
HTHS,
Чарльз