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