[英]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.