Как я должен внедрить Autorest Client с TokenProvider, используя autofac в asp.net mvc 5? - PullRequest
0 голосов
/ 31 мая 2019

Я хочу правильно внедрить клиентскую зависимость autorest, которая использует api (у которых пользователи будут использовать свой собственный токен после входа в систему, но они могут использовать api до входа в систему для некоторых методов, токен не требуется) с помощью autofac. Я знаю, что это не вопрос автостопа, а скорее об автофактуре, но я хочу привести точный пример, чтобы получить более точную рекомендацию (возможно, я все делаю неправильно, это концептуальная проблема). Я искал некоторые примеры, которые я нашел, но во всех них они были реализацией только для одного пользователя, которого они не использовали tokenprovider, они просто передали неизвестный токен (который не является токеном для пользователя, это для приложения).

То, что я пытался, это зарегистрировать клиент autorest с обернутым параметром (уже зарегистрированные множественные зависимости принимают друг друга в качестве параметров конструктора) в контейнер.

Вот так я регистрирую свои услуги:

protected void Application_Start()
{

    var builder = new ContainerBuilder();
    builder.RegisterControllers(Assembly.GetExecutingAssembly());


    var sp = ServicePointManager.FindServicePoint(new Uri(ConfigurationManager.AppSettings["WebApiBaseUrl"]));
    sp.ConnectionLeaseTimeout = 60 * 1000; // 1 minute
    builder.Register(c => new HttpContextWrapper(HttpContext.Current))
        .As<HttpContextBase>()
        .InstancePerRequest();
    builder.RegisterType<TokenProvider>().As<ITokenProvider>().InstancePerLifetimeScope();
    builder.RegisterType<TokenCredentials>().Keyed<ServiceClientCredentials>("credentials").InstancePerLifetimeScope();
    builder.RegisterType<WebApiClient>()
           .As<IWebApiClient>()
           .WithParameter("baseUri", new Uri(ConfigurationManager.AppSettings["WebApiBaseUrl"])
           ).WithParameter("credentials",
              new ResolvedParameter(
   (pi, ctx) => pi.ParameterType == typeof(ServiceClientCredentials),
   (pi, ctx) => ctx.ResolveKeyed<ServiceClientCredentials>(pi.Name))
   ).SingleInstance();


    IContainer container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

}

и мои услуги:

public partial class WebApiClient : ServiceClient<WebApiClient>, IWebApiClient
{

    public WebApiClient(System.Uri baseUri, ServiceClientCredentials credentials = null, params DelegatingHandler[] handlers) : this(handlers)
    {
        if (baseUri == null)
        {
            throw new System.ArgumentNullException("baseUri");
        }

        BaseUri = baseUri;

        if (credentials != null)
        {
            Credentials = credentials;
            Credentials.InitializeServiceClient(this);
        }
    }
}
public class TokenProvider : ITokenProvider
{
    private readonly HttpContextBase _context;

    public TokenProvider(HttpContextBase context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
    {
        // this should be async i know(another topic to ask in mvc 5)
        var token =_context.Session["ServiceToken"]?.ToString();
        if (string.IsNullOrWhiteSpace(token))
        {
            throw new InvalidOperationException("Could not get an access token from HttpContext.");
        }

        return new AuthenticationHeaderValue("Bearer", token);
    }
}

public class TokenCredentials : ServiceClientCredentials
{
    //I want to use this constructor
    public TokenCredentials(ITokenProvider tokenProvider);
}

Это исключение, которое я получаю

Внутреннее исключение Невозможно привести объект типа Autofac.Core.ResolvedParameter к типу Microsoft.Rest.ServiceClientCredentials.

Ответы [ 2 ]

1 голос
/ 31 мая 2019

Невозможно привести объект типа Autofac.Core.ResolvedParameter к типу Microsoft.Rest.ServiceClientCredentials.

означает, что вы используете объект ResolvedParameter, тогда как ожидается ServiceClientCredentials.

В вашем коде есть

.WithParameter("credentials",
     new ResolvedParameter(
       (pi, ctx) => pi.ParameterType == typeof(ServiceClientCredentials),
       (pi, ctx) => ctx.ResolveKeyed<ServiceClientCredentials>(pi.Name))
     )

WithParameter имеет 3 перегрузки:

  • WithParameter(string parameterName, object parameterValue): когда вы знаете имя параметра иВы можете предоставить его во время регистрации. Autofac создаст для вас объект NamedParameter.
  • WithParameter(Func<ParameterInfo, IComponentContext, bool> parameterSelector, Func<ParameterInfo, IComponentContext, object> valueProvider): если вы не знаете имя параметра и / или когда вы не можете указать значение ввремя регистрации. Autofac создаст для вас ResolvedParameter объект.
  • WithParameter(Parameter parameter): для предоставления Parameter объекта, который вы создаете сами.

В вашемЕсли вы используете первый вариант. Autofac создаст для вас NamedParameter, а вы укажите ResolvedParameter в качестве значения.

Чтобы исправить ошибку, вы не должны использовать первую перегрузку таким образом, но вы можете использовать вторую:

.WithParameter((pi, ctx) => pi.ParameterType == typeof(ServiceClientCredentials),
               (pi, ctx) => ctx.ResolveKeyed<ServiceClientCredentials>(pi.Name)))
0 голосов
/ 05 июня 2019

Мой окончательный код теперь похож на. (Теперь он работает без каких-либо проблем. Но если у вас есть какие-либо рекомендации или замечания по поводу этого кода, не стесняйтесь сообщить, пожалуйста.)

 builder.Register(c => new HttpContextWrapper(HttpContext.Current) as HttpContextBase)
               .As<HttpContextBase>().InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Request)
               .As<HttpRequestBase>().InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Response)
               .As<HttpResponseBase>().InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Server)
               .As<HttpServerUtilityBase>().InstancePerLifetimeScope();
            builder.Register(c => c.Resolve<HttpContextBase>().Session)
               .As<HttpSessionStateBase>().InstancePerLifetimeScope();
            builder.RegisterType<TokenProvider>().As<ITokenProvider>().InstancePerLifetimeScope();
            builder.RegisterType<TokenCredentials>().Keyed<ServiceClientCredentials>("credentials").InstancePerLifetimeScope();
            builder.RegisterType<WebApiClient>()
                   .As<IWebApiClient>()
                   .WithParameter("baseUri", new Uri(ConfigurationManager.AppSettings["WebApiBaseUrl"])
                   )
                   .WithParameter((pi, ctx) => pi.ParameterType == typeof(ServiceClientCredentials),
               (pi, ctx) => ctx.ResolveKeyed<ServiceClientCredentials>(pi.Name))
           .InstancePerLifetimeScope();

И мой поставщик токенов;

public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
        {
            string token = "NonAuthorizedUserDummyToken";
            await Task.Delay(500);
            token = _context.Session?["ServiceToken"]?.ToString();
            return new AuthenticationHeaderValue("Bearer", token);
        }
...