将ApplicationModel的实例注入到MVC服务中,该服务本身将是单例 [英] injectiong an instance of ApplicationModel into an MVC service which will itself be a singleton

查看:216
本文介绍了将ApplicationModel的实例注入到MVC服务中,该服务本身将是单例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅当主体可以访问导航树的各个组件(无论是基于角色还是基于策略)时,我才希望显示它们.

I would like to display components of a navigation tree only if a principal has access to those components (whether roles or policy based).

我对MVC内核不是特别熟悉,但是到目前为止,我会读到这表示我可以建立一个列表,该列表可以将类似于以下内容的授权过滤器应用于某项操作:

I am not particularly familiar with MVC core, but reading to date would indicate that I could build a list of what authorization filters will be applied to an action with something like:

    public NavigationNodePermissionResolver(ApplicationModel appModel)
    {
        foreach (var controllerModel in appModel.Controllers)
        {
            var contextFilters = controllerModel.Filters.OfType<IAsyncAuthorizationFilter>().ToList();
            foreach (ActionModel action in controllerModel.Actions)//todo restrain to HttpGet
            {
                var actionFilters = action.Filters.OfType<IAsyncAuthorizationFilter>().ToList();
            }
        }

如何将应用程序模型的实例注入到NavigationNodePermissionResolver的实例化器中?

How can I inject an instance of the application model into the instantiator for NavigationNodePermissionResolver?

NavigationNodePermissionResolver本身可以按以下方式注入:

NavigationNodePermissionResolver itself will be injectable as:

services.TryAddSingleton<INavigationNodePermissionResolver, NavigationNodePermissionResolver>();

修改

此问题的后续解答-当我有IAsyncAuthorizationFilters列表时该怎么办

the follow on to this question - what to do when I have a list of the IAsyncAuthorizationFilters is in this so question.

作为后续信息,ApplicationModel是ApplicationModelProviderContext的属性,我在

as follow up information the ApplicationModel is a property of the ApplicationModelProviderContext which I found out about in this SO answer - it does seem to be roughly what I am after, but it may be the approach I am using to obtain and then execute authorization filters is completely wrong

推荐答案

我发现我可以实例化并注入实现2个接口的相同实例.我最终进入Startup.ConfigureServices:

I discovered I can instantiate and inject the same instance which implements 2 interfaces. I ended up within Startup.ConfigureServices:

var customAppModelProvider = new CustomApplicationModelProvider();
services.AddSingleton<IApplicationModelProvider>(customAppModelProvider);
services.AddSingleton<IActionFilterMap>(customAppModelProvider);

执行:

public interface IActionFilterMap
{
    IEnumerable<IAsyncAuthorizationFilter> GetFilters(string area, string controller, string action);
}
public class CustomApplicationModelProvider : IApplicationModelProvider, IActionFilterMap
{
    //It will be executed after AuthorizationApplicationModelProvider, which has order -990
    public int Order => 0;

    private ReadOnlyDictionary<ActionKey, IEnumerable<IAsyncAuthorizationFilter>> _authDictionary;

    public IEnumerable<IAsyncAuthorizationFilter> GetFilters(string area, string controller, string action)
    {
        var key = new ActionKey(area, controller, action);
        if (_authDictionary.TryGetValue(key, out IEnumerable<IAsyncAuthorizationFilter> returnVar))
        {
            return returnVar;
        }
        return null;//returning null rather than Enumerable.Empty so consuming method can detect if action found and has no Authorization, or action not found

    }

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
        var returnVar = new Dictionary<ActionKey, IEnumerable<IAsyncAuthorizationFilter>>();
        foreach (var controllerModel in context.Result.Controllers)
        {
            var controllerFilters = controllerModel.Filters.OfType<IAsyncAuthorizationFilter>().ToList();
            string area = controllerModel.Attributes.OfType<AreaAttribute>().FirstOrDefault()?.RouteValue;
            foreach (ActionModel action in controllerModel.Actions)//todo restrain to get
            {
                var method = action.Attributes.OfType<HttpMethodAttribute>().FirstOrDefault();
                if (method == null || method.HttpMethods.Contains("GET"))
                {
                    var key = new ActionKey(area, controllerModel.ControllerName, action.ActionName);
                    if (action.Filters.OfType<AllowAnonymousFilter>().Any())
                    {
                        returnVar.Add(key, Enumerable.Empty<IAsyncAuthorizationFilter>());
                    }
                    else
                    {
                        var filters = controllerFilters.Concat(action.Filters.OfType<IAsyncAuthorizationFilter>()).ToArray();
                        returnVar.Add(key, filters);
                    }
                }
            }
            _authDictionary = new ReadOnlyDictionary<ActionKey, IEnumerable<IAsyncAuthorizationFilter>>(returnVar);
        }
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        //empty
    }

    private class ActionKey : Tuple<string, string, string>
    {
        public ActionKey(string area, string controller, string action) : base(area ?? string.Empty, controller, action)
        {
            _hashCode = base.GetHashCode();
        }

        int _hashCode;
        public override int GetHashCode()
        {
            return _hashCode;
        }
    }
}

这篇关于将ApplicationModel的实例注入到MVC服务中,该服务本身将是单例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆