最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

C# AWS Lambda Annotation Functions never passes through middleware - Stack Overflow

matteradmin5PV0评论

I'm writing C# Lambda functions to be exposed by the API Gateway service, using the AWS Annotation Framework.

I successfully registered application services in the ConfigureServices(IServiceCollection services) method of the Startup.cs file.

In order to add some API configurations in the header of all incoming requests (Authorization header, etc.), I registered a middleware via the Configure(IApplicationBuilder app, IWebHostEnvironment env) method of the the Startup.cs file.

The problem is, the application is completely ignoring the middleware; in other terms, the application never passes through the middleware.

Here is my code:

Lambda function (in Function.cs file):

using Amazon.Lambda.Core;
using Amazon.Lambda.Annotations;
using TbTypes.Model.Api.Requests;
using Microsoft.AspNetCore.Mvc;
using FromServicesAttribute = Amazon.Lambda.Annotations.FromServicesAttribute;
using FromBodyAttribute = Microsoft.AspNetCore.Mvc.FromBodyAttribute;
using TbTypes.Services.Thingsboard;
using TbTypes.Model.Api.Reponses;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace TbInterface;

public class Function
{
    /// <summary>
    /// Function for requesting TB Devices visible by a User
    /// </summary>
    [LambdaFunction()]
    [HttpGet("/user/devices/")]
    public async Task<DevicesPage> FetchDevices(
        [FromBody] UserDevicesRequestBody body,
        ILambdaContext context,
        [FromServices] IDeviceService service)
    {
       // you can replace IDeviceService by a dummy service when reproducing the issue
        return await service.FetchDevices(body.claims.TbUserID, body.claims.CognitoUserID);
    }
}

My Startups.cs file with services registration in ConfigureServices() and middleware registration in Configure() method:

using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Lambda.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Diagnostics;
using TbInterface.Configuration;
using TbInterface.Middlewares;
using TbInterface.Repositories;
using TbInterface.Services.Cache;
using TbInterface.Services.Database;
using TbInterface.Services.Thingsboard;
using TbTypes.Configuration;
using TbTypes.Repositories;
using TbTypes.Services.Cache;
using TbTypes.Services.Thingsboard;

namespace TbInterface
{
    [LambdaStartup]
    public class Startup
    {
        private IConfiguration Configuration;

        public Startup()
        {
            Configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables()
            .Build();
        }

        public void ConfigureServices(IServiceCollection services)
        {

            // Application Configurations
            services.AddSingleton<IConfiguration>(implementationInstance: Configuration);
            services.AddSingleton<ITbConfiguration>(sp => {
                var settings = sp.GetRequiredService<IConfiguration>();
                return new TbConfiguration(settings);
            });

            // Cache Service: AWS Elasti Cache
            services.AddSingleton<IElastiCacheService, ElastiCacheService>();

            // Database Service: AWS DynamoDB
            services.AddSingleton<IAmazonDynamoDB, DynamoDB>();
            services.AddAWSService<IAmazonDynamoDB>();
            //services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
            services.AddAWSService<Amazon.S3.IAmazonS3>();
            services.AddAWSService<IAmazonDynamoDB>();


            // Repositories
            services.AddSingleton<IUserTokenRepository, UserTokenRepository>();

            // Thingsboard API services
            services.AddSingleton<IAuthTokenService, AuthTokenService>();
            services.AddSingleton<IUserService, UserService>();
            services.AddSingleton<IDeviceService, DeviceService>();
            services.AddTransient<TbApiConfigurationMiddleware>();

        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
           // Here's how I resgistered the middleware
            app.UseMiddleware<TbApiConfigurationMiddleware>();
        }

    }
}

The middleware itself - TbApiConfigurationMiddleware.cs :

using Microsoft.AspNetCore.Http;
using System.Net;
using Newtonsoft.Json;
using TbAPIClient.Generated.Client;
using TbAPIClient.Generated.Model;
using TbClientConfiguration = TbAPIClient.Generated.Client.Configuration;
using TbTypes.Model.Api.Requests;
using TbTypes.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace TbInterface.Middlewares
{
    public class TbApiConfigurationMiddleware : IMiddleware
    {
        /// <summary>
        /// Custom logic to be executed before the next middleware
        /// </summary>
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var authService = context.RequestServices.GetService<IAuthTokenService>();

            BaseApiRequestBody? body = extractRequestBody(context);

            if (body == null || body.claims == null) {
                await handleBadRequestBody(context, "Bad request body format");
                return;
            }

            //JwtPair? token = await _authService.RetrieveOrRequestUserToken(body.claims.TbUserID!);
            JwtPair? token = await authService!.FetchUserTokenAsync(body.claims.TbUserID!);

            if (token == null)
            {
                await handleUnauthorizedUser(context);
                return;
            }

            var tbConfiguration = context.RequestServices.GetService<ITbConfiguration>();
            ConfigureTbApiToken(token!, tbConfiguration!);

            await next(context);
        }

        /// <summary>
        /// Extract request body to perform basic format validation
        /// </summary>
        /// <param name="context">HTTP Context</param>
        /// <returns></returns>
        private BaseApiRequestBody? extractRequestBody(HttpContext context) {
            var rawBody = context.Request.Body.ToString();

            if (rawBody == null)
            {
                return null;
            }

            return JsonConvert.DeserializeObject<BaseApiRequestBody>(rawBody);
        }

        /// <summary>
        /// Handling bad request body
        /// </summary>
        /// <param name="context">HTTP Context</param>
        /// <returns></returns>
        private async Task handleBadRequestBody(HttpContext context, string message) {
            context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            context.Response.ContentType = "application/json";
            var body = new ApiException(context.Response.StatusCode, message);
            await context.Response.WriteAsync(JsonConvert.SerializeObject(body));
        }


        /// <summary>
        /// Configuring middleware response in case of Unauthorized User
        /// </summary>
        /// <param name="context">HTTP Context</param>
        /// <returns></returns>
        private async Task handleUnauthorizedUser(HttpContext context)
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            context.Response.ContentType = "application/json";
            var body = new ApiException(context.Response.StatusCode, "Unauthorized user");
            await context.Response.WriteAsync(JsonConvert.SerializeObject(body));
        }

        /// <summary>
        /// Method for configuring Thingsboard API Auth Token
        /// </summary>
        /// <param name="token">Token definition: {Token, RefreshToken} </param>
        /// <param name="tbConfiguration">Application configs </param>
        /// <returns></returns>
        private void ConfigureTbApiToken(JwtPair token, ITbConfiguration tbConfiguration)
        {
            TbClientConfiguration.Default.ApiKeyPrefix[tbConfiguration.TokenHeaderKey] = tbConfiguration.TokenType;
            TbClientConfiguration.Default.ApiKey[tbConfiguration.TokenHeaderKey] = (string)token.Token;
        }
    }
}

Post a comment

comment list (0)

  1. No comments so far