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,
Чарльз

Другие вопросы по тегам