c#如何获得异步调用方法的方法名



我有一个由两个项目组成的解决方案,一个Blazor服务器网站和一个类库。在类库中,我创建了一个类,允许我向库中其他类中的函数添加自定义属性。这允许我用可以访问函数的角色来修饰函数。然后调用一个类来提取这些标签并检查数据库是否一致。当调用函数是一个常规函数时,这很好地工作。但是,如果它是一个异步函数,我正在查看的堆栈帧返回值为"而不是方法的名称。是否有一种方法来获得调用方法的方法名,如果该方法是异步的?下面是我的伪代码:

添加自定义属性:

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");
}                
}
}

CanUserEditProgram在_userRights中的函数

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));
}
}
}
定义一个结果类。没有严格要求,您可以为未实现返回null,…这只是为您提供了一个方法来返回结果和数据,而无需诉诸out。您可以在新的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事件,以便在用户更改时更新角色。