簡體   English   中英

C#如果異步,如何獲取調用方法的方法名稱

[英]C# How to get the method name of the calling method if async

我有一個由兩個項目組成的解決方案,一個 Blazor 服務器網站和一個類庫。 在類庫中,我創建了一個類,允許我向庫中其他類中的函數添加自定義屬性。 這允許我用可以訪問該函數的角色來裝飾一個函數。 然后我有一個類被調用來提取這些標簽並檢查數據庫是否一致。 當調用函數是常規函數時,這很好用。 但是,如果它是一個異步函數,我正在查看的堆棧幀將返回“MoveNext”的值而不是方法的名稱。 如果該方法是異步的,有沒有辦法獲取調用方法的方法名稱? 這是我的偽代碼:

添加自定義屬性的類:

namespace DataAccessLibrary
{
    [AttributeUsage(AttributeTargets.Method |AttributeTargets.ReturnValue)]
    public class MELAdvanceRoles: Attribute
    {
        public string[] _Roles { get; set; }
        public MELAdvanceRoles(string[] roles)
        {
            _Roles = roles;           
        }
    }
}

使用自定義屬性的示例函數:

namespace DataAccessLibrary
{
    public class ProgramData: IProgramData
    {
        private readonly ISqlDataAccess _db;      
        private readonly IUserRights _userRights;

        public ProgramData(ISqlDataAccess db, IUserRights userRights)
        {
            _db = db;            
            _userRights = userRights;
        }   
        [MELAdvanceRoles(new string[] { "MANAGER", "EMPLOYEE", "READ_ONLY" })]
        public async Task<int> UpdateProgram(ProgramModel program)
        {   
            if (_userRights.CanUserEditProgram(program.id))
                //protected stuff
            }
            else
            {
                throw new Exception("403 Forbidden");
            }                
        }
}

_userRights 中的 CanUserEditProgram 函數

public bool CanUserEditProgram(int program_id)
{         
    //get roles in the custom attribute  
    string[] allowed_roles = GetMethodRoles();
    // use that list for database stuff
}

public string[] GetMethodRoles()
{
    string[] roles = { };
    StackTrace stackTrace = new StackTrace();
    //it seems that functions that are async are not on the second frame
    string methodName = stackTrace.GetFrame(2).GetMethod().Name;
    //mehtodname returns 'MoveNext' if the calling method is async
    MethodInfo mInfo = stackTrace.GetFrame(2).GetMethod().ReflectedType.GetMethod(methodName);
    //which means mInfo returns null
    bool isDef = Attribute.IsDefined(mInfo, typeof(MELAdvanceRoles));
    if (isDef)
    {
        MELAdvanceRoles obsAttr = (MELAdvanceRoles)Attribute.GetCustomAttribute(mInfo, typeof(MELAdvanceRoles));
        if (obsAttr != null)
        {
            roles = obsAttr._Roles;
        }
    }
    return roles;
}

謝謝

最初認為這是一個瘋狂的想法,我很感興趣,可以探索如果必須的話我將如何解決這個問題。 這是一個可能的方法的第一個演示哈希。

定義所有具有授權的類都需要實現的接口。

using System;
using System.Collections.Generic;

namespace StackOverflow.Answers
{
    public interface IClassAuthorization
    {
        public List<string> UserRoles { get; set; }

        public Boolean UserHasRole(string role)
        {
            if (UserRoles is null)
                throw new ApplicationException("No UserRoles defined for object.  If you are using Class Authorization you must set the UserRoles");
            return UserRoles.Any(item => item.Equals(role, StringComparison.CurrentCultureIgnoreCase));
        }
    }
}

定義一個結果類。 不嚴格要求,您可以為未實現返回空值,...這只是為您提供了一種無需求助於輸出即可返回結果和數據的方法。 您可以在新的 WeatherForecastService 中看到所有三個實現。

namespace StackOverflow.Answers
{
    public class ClassAuthorizationResult
    {
        public ClassAuthorizationResultType Status { get; private set; } = ClassAuthorizationResultType.NotDefined;

        public object Data { get; set; } = null;

        public static ClassAuthorizationResult Success(object data)
            => new ClassAuthorizationResult { Status=ClassAuthorizationResultType.Success, Data = data };

        public static ClassAuthorizationResult Failure()
            => new ClassAuthorizationResult { Status = ClassAuthorizationResultType.Failure, Data = null };

        public static ClassAuthorizationResult NotDefined()
            => new ClassAuthorizationResult { Status = ClassAuthorizationResultType.NotDefined, Data = null };

        public enum ClassAuthorizationResultType
        {
            NotDefined,
            Success,
            Failure
        }
    }
}

這是新的 WeatherForecastService:

using StackOverflow.Answers.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace StackOverflow.Answers
{
    public class AuthorizedWeatherForecastService : IClassAuthorization
    {
        public List<string> UserRoles { get; set; } = null;

        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private IClassAuthorization _interface => this;

        private List<WeatherForecast> records;

        public AuthorizedWeatherForecastService()
        {
            records = GetWeatherForecasts;
        }

        //  Null return
        public Task<List<WeatherForecast>> ForecastsAsync()
            => Task.FromResult(_interface.UserHasRole("User")
                ? this.records
                : null);
        
        // ClassAuthorizationResult return
        public Task<ClassAuthorizationResult> GetForecastsAsync()
            => Task.FromResult(_interface.UserHasRole("User")
                ? ClassAuthorizationResult.Success(this.records)
                : ClassAuthorizationResult.Failure());

        // Out return
        public Task<bool> GetForecastsAsync(out List<WeatherForecast> list)
        {
            var ok = _interface.UserHasRole("User");
            list = ok ? this.records : new List<WeatherForecast>();
            return Task.FromResult(ok);
        }

        private List<WeatherForecast> GetWeatherForecasts
        {
            get
            {
                var rng = new Random();
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary = Summaries[rng.Next(Summaries.Length)]
                }).ToList();
            }
        }
    }
}

然后在FetchData

    [Inject] AuthorizedWeatherForecastService ForecastService { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ForecastService.UserRoles = new List<string> { "User" };
        var result = await ForecastService.GetForecastsAsync();
        if (result.Status == ClassAuthorizationResult.ClassAuthorizationResultType.Success)
            forecasts = (List<WeatherForecast>)result.Data;
    }

您可以從 AuthenticationState 獲取用戶角色。 如果您的類是服務,則直接注入 IAuthenticationStateProvider 並注冊AuthenticationStateChanged事件以在用戶更改時更新角色。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM