简体   繁体   中英

C# Performant method caller attribute usage

I am writing a client library for an API that provides both public and authenticated endpoints. I would like to easily denote which endpoints require authentication using attributes. For instance:

public async Task<ApiResponse> GetPublicData()
{
  var request = CreateRequest( "v1/public" );
  return await _httpClient.GetAsync( request );
}

[RequiresAuthentication]
public async Task<ApiResponse> GetPrivateData()
{
  var request = CreateRequest( "v1/private" );
  return await _httpClient.GetAsync( request );
}

private ApiRequest CreateRequest( string endpoint )
{
   var request = new ApiRequest( endpoint );

   // if (caller has RequiresAuthenticationAttribute)
   //    SignRequest( request, _credentials );

   return request;
}

As far as I am aware, the only way I can access whether or not the caller of CreateRequest has a RequiresAuthenticationAttribute is to create a stack frame, find the method via reflection, and then attempt to get the attribute from the MethodInfo . This can be incredibly slow.

Is there any other way to pass this information into the callee that won't kill performance. I know that the requests will always be limited by the response time of the API, but given that it has to do with financial data, being able to fire off requests as soon as possible is a must, and being able to do it in a clean way that involves attributes instead of manually passing parameters would be very nice.

You could try using the CallerMemberNameAttribute class .

The attributes "Allows you to obtain the method or property name of the caller to the method."

private ApiRequest CreateRequest(string endpoint, [CallerMemberName] string callerMemberName= "")
{
    var methodInfo = this.GetType().GetMethod(callerMemberName);
    var attributes = (RequiresAuthenticationAttribute)method.GetCustomAttributes(typeof(RequiresAuthenticationAttribute), true);

    var request = new ApiRequest( endpoint );

    if (attributes.Any())
        SignRequest(request, _credentials);

    return request;
}

If you are set on using attributes, then you are going to have to use Reflection in one way or another. Some reflection mechanisms are faster than others, but there is still a runtime penalty which you will have to pay. On the other hand, if what you want is a separation of concerns (and using attributes is not a given), then you might want to think about using interfaces to separate those concerns.

For example:

public interface IAuthenticated
{
  public async Task<ApiResponse> GetPrivateData();
}

public interface IPublicAccess
{
  public async Task<ApiResponse> GetPublicData();
}

public async Task<ApiResponse> IPublicAccess.GetPublicData()
{
  var request = CreateRequest( "v1/public" );
  return await _httpClient.GetAsync( request );
}

public async Task<ApiResponse> IAuthenticated.GetPrivateData()
{
  var request = CreateRequest( "v1/private" );
  return await _httpClient.GetAsync( request );
}

private ApiRequest CreateRequest( string endpoint )
{
   var request = new ApiRequest( endpoint );

   // if (caller has RequiresAuthenticationAttribute)
   //    SignRequest( request, _credentials );

   return request;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM