I have a URL for like below:
https://localhost:44351/odata/PublicInsuranceOrder('To New1')
for it i have created below dotnet core controller which is working
[ODataRoutePrefix("PublicInsuranceOrder")]
public class PublicInsuranceOrderController : ODataController
{
[HttpGet]
[EnableQuery]
[SwaggerResponse("200", typeof(PublicInsuranceOrder))]
[SwaggerResponse("404", typeof(void))]
[ODataRoute("({insuranceOrderName})")]
public ActionResult<PublicInsuranceOrder> Get([FromODataUri] string insuranceOrderName)
{
//this works
}
Now I have a API with below route:
https://localhost:44351/odata/PublicInsuranceOrder('To New1') /Claim('1')
I have tried below controller method for it which is not working
[HttpGet]
[EnableQuery]
[SwaggerResponse("200", typeof(PublicInsuranceOrder))]
[SwaggerResponse("404", typeof(void))]
[ODataRoute("({insuranceOrderName})/Claim({id})")]
public ActionResult<PublicInsuranceOrder> Get([FromODataUri] string insuranceOrderName, string id)
{
//Not working
}
My startup.cs is like this:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddEnvironmentVariables();
builder.AddJsonFile(env.IsDevelopment() ? "appsettings.Development.json" : "appsettings.json", false, false);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureServices(Configuration, typeof(WomBCModule), "Wom");
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // _2);
services.AddTransient<PublicWorkOrder>();
services.AddOData();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Configure(env, true);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc(routeBuilder =>
{
routeBuilder.EnableDependencyInjection();
// expand refs / which attr / query / count
//routeBuilder.Expand().Select().Filter().Count()
routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
//routeBuilder.MapODataServiceRoute("odata", "odata/v1", GetEdmModel());
//routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
// Create the default collection of built-in conventions.
var conventions = ODataRoutingConventions.CreateDefault();
// Insert the custom convention at the start of the collection.
conventions.Insert(0, new NavigationIndexRoutingConvention());
routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel(), new DefaultODataPathHandler(), conventions);
});
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<PublicWorkOrder>("PublicInsuranceOrder");
builder.EntitySet<Claim>("Claim");
return builder.GetEdmModel();
}
}
I have created a NavigationIndexRoutingConvention as shown below:
public partial class NavigationIndexRoutingConvention : IODataRoutingConvention
{
IEnumerable<ControllerActionDescriptor> IODataRoutingConvention.SelectAction(RouteContext routeContext)
{
// Get a IActionDescriptorCollectionProvider from the global service provider
IActionDescriptorCollectionProvider actionCollectionProvider =
routeContext.HttpContext.RequestServices.GetRequiredService<IActionDescriptorCollectionProvider>();
Contract.Assert(actionCollectionProvider != null);
// Get OData path from HttpContext
Microsoft.AspNet.OData.Routing.ODataPath odataPath = routeContext.HttpContext.ODataFeature().Path;
HttpRequest request = routeContext.HttpContext.Request;
// Handle this type of GET requests: /odata/Orders(1)/OrderRows(1)
if (request.Method == "GET" && odataPath.PathTemplate.Equals("~/entityset/key/navigation/key"))
{
// Find correct controller
string controllerName = odataPath.Segments[3].Identifier;
IEnumerable<ControllerActionDescriptor> actionDescriptors = actionCollectionProvider
.ActionDescriptors.Items.OfType<ControllerActionDescriptor>()
.Where(c => c.ControllerName == controllerName);
if (actionDescriptors != null)
{
// Find correct action
string actionName = "Get";
var matchingActions = actionDescriptors
.Where(c => String.Equals(c.ActionName, actionName, StringComparison.OrdinalIgnoreCase) && c.Parameters.Count == 2)
.ToList();
if (matchingActions.Count > 0)
{
// Set route data values
var keyValueSegment = odataPath.Segments[3] as KeySegment;
var keyValueSegmentKeys = keyValueSegment?.Keys?.FirstOrDefault();
routeContext.RouteData.Values[ODataRouteConstants.Key] = keyValueSegmentKeys?.Value;
var relatedKeyValueSegment = odataPath.Segments[1] as KeySegment;
var relatedKeyValueSegmentKeys = relatedKeyValueSegment?.Keys?.FirstOrDefault();
routeContext.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeyValueSegmentKeys?.Value;
// Return correct action
return matchingActions;
}
}
}
// Not a match
return null;
}
}
I am getting below error:
404 NOT FOUND
Can i know what i am doing wrong
Related
I have Asp.net core(running on .net framework) web mvc application.
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var aiOptions = new Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions
{
EnableQuickPulseMetricStream = true
};
services.AddMvc();
services.AddApplicationInsightsTelemetry(aiOptions);
services.AddCors(option =>
{
option.AddPolicy("AllowSpecificOrigin", policy => policy.WithOrigins("*"));
option.AddPolicy("AllowGetMethod", policy => policy.WithMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
TelemetryClient tc = new TelemetryClient();
tc.TrackTrace("Environment: " + env);
if (env.IsDevelopment())
{
tc.TrackTrace("Development");
app.UseDeveloperExceptionPage();
}
else
{
app.UseDeveloperExceptionPage();
}
app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/Application1");
return next.Invoke();
});
app.UseStaticFiles();
app.UseCors(select => select.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
}
}
HomeController Action:
public class HomeController : Controller
{
public HomeController(StatelessServiceContext context){
}
public IActionResult UsernameAuthentication()
{
return View();
}
}
Action Executing:
http://localhost:9040/Home/UserNameAuthentication
Action not Executing:
http://localhost:9040/Application1/Home/UserNameAuthentication
Any other configuration i have to do,to execute Action with PathBase?or any other way to use context path to execute action.How?
Thanks.
As far as I know, if you use Application1/Home/UserNameAuthentication as the url pass to the application, the application context.Request.Path will be the Application1/Home/UserNameAuthentication then you add the pathbase, it will be Application1/Application1/Home/UserNameAuthentication this is the reason why you get 404 error.
To solve this issue, you should check whether the beginning of this Microsoft.AspNetCore.Http.PathString matches the specified Microsoft.AspNetCore.Http.PathString.
More details, you could refer to below codes:
app.Use((context, next) =>
{
string _pathBase = "/Application1";
PathString matchedPath;
PathString remainingPath;
if (context.Request.Path.StartsWithSegments(_pathBase, out matchedPath, out remainingPath))
{
var originalPath = context.Request.Path;
var originalPathBase = context.Request.PathBase;
context.Request.Path = remainingPath;
context.Request.PathBase = originalPathBase.Add(matchedPath);
var re = context.Request.PathBase;
return next.Invoke();
}
else
{
return next.Invoke();
}
});
Result:
I've created a new controller in a brand new web api project in .net core 3.1. Whenever I try to post to the route I get a 404.
The controller is set as so:
[ApiController]
[Route("[controller]")]
public class AuthCodeController : Controller
{
private readonly ApplicationContext _context;
public AuthCodeController(ApplicationContext context)
{
_context = context;
}
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public JsonResult GetAuthCode(AuthCode authCode)
{
try
{
var theCodes = _context.AuthCodes.ToList();
var tmpCode = new Random();
var myNum = tmpCode.Next(100000, 999999999);
while (theCodes.Any(tc => tc.AuthCodeRnd == myNum))
{
myNum = tmpCode.Next();
}
if (authCode.AuthCodeRnd > 0)
{
var removeCode = _context.AuthCodes.FirstOrDefault(c => c.AuthCodeRnd == authCode.AuthCodeRnd);
if (removeCode != null) _context.AuthCodes.Remove(removeCode);
}
Guid authGuid = Guid.NewGuid();
var tmpRec = new AuthCode
{
Guid = authGuid,
AuthCodeRnd = myNum,
Address = authCode.tAddress,
SmallLogoAddress = authCode.SmallLogoAddress,
ClientFolder = authCode.ClientFolder,
CompanyFolder = authCode.CompanyFolder,
Folder = authCode.Folder
};
_context.AuthCodes.Add(tmpRec);
_context.SaveChanges();
var retVals = new AuthResponse
{
Guid = authGuid,
ReturnAuthCode = myNum
};
return Json(retVals);
}
catch (Exception ex)
{
var message = new ErrorResponse();
message.Status = "An Error Has Occured";
message.Message = ex.ToString();
return Json(message);
}
}
}
When I POST to this method I receive a 404. I'm using the url https://localhost:44328/AuthCode/GetAuthCode
The only modifications I made in the startup.cs are adding the dbcontext service options. Everything else is default. I can get the weatherforecast to show.
EDIT - added startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Solved: I needed to disable SSL Verification in POSTMan
You should set attribute: [HttpPost] → [HttpPost("GetAuthCode")] since your original route will be simple POST to 'https://localhost:44328/AuthCode'. Core Controller does use reflection to Your Controller name 'AuthCodeController' to form prefix for Your path ('/AuthCode' part). But it does not use reflection to form postfix from function name - You should form it yourself by parameter in HttpPost attribute.
I defined a simple view where I request the user to choose a file to upload.
This file is stored in a model (model of the view) and is then treated in the POST method.
Once the file has been uploaded, I save the new model (result of the file) it into the TempData in order to pass it to the next view to be displayed and later validate the content by the user.
Everything works fine until the redirecttoaction which is not doing anything and I don't know what I'm doing wrong here
Here is an example of what I do:
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(ImportIndexViewModel model)
{
if (!ModelState.IsValid)
return View(model);
if (model.File == null)
{
ModelState.AddModelError("File", "File is null");
return View(model);
}
var extension = Path.GetExtension(model.FileName);
if (extension != ".xlsx")
{
ModelState.AddModelError("File extension", "File type is not authorized. Please use the correct template file");
return View(model);
}
var uploads = Path.Combine(_webHostEnvironment.WebRootPath, "uploads");
if (model.File.Length <= 0)
{
ModelState.AddModelError("File size", "File length is <= 0");
return View(model);
}
var resultModel = InterclubsApiClient.GetInterclubsReaderModel(model.File, uploads).GetAwaiter().GetResult();
TempData.Put<InterclubsReaderModel>("InterclubsReaderModel", resultModel);
return RedirectToAction(nameof(ImportController.Upload), typeof(ImportController).GetControllerName());
}
[HttpGet]
public IActionResult Upload()
{
var model = TempData.Get<InterclubsReaderModel>("InterclubsReaderModel");
if (model == null)
return BadRequest(ErrorHelper.GetModelStateDictionary("InterclubsReaderModel", "Model is null when retrieved from TempData"));
return View(model);
}
Upload is working because I can find the file in the uploads folder. The model is also correct because I can find values into it but why the redirect isn't working ?
Instead, the page stays there and I can't do anything on it. If I use Chrome, it says that the website isn't reachable (like missing the link to IIS).
Thanks for your help.
EDIT: In answer to the question: are you sure this is the correct method name given by nameof(...)
Here it is:
SECOND EDIT:
Do you guys think something is wrong here ?
public class Startup
{
public IConfiguration Configuration { get; }
public IWebHostEnvironment Environment { get; }
#region Constructor
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Environment = env;
}
#endregion
#region Configure services
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services
.AddAuthentication("InterclubsCookieAuth")
.AddCookie("InterclubsCookieAuth", config =>
{
config.Cookie.Name = "Interclubs.Cookie";
config.LoginPath = "/Connect/Login";
config.LogoutPath = "/Connect/Logout";
config.ExpireTimeSpan = TimeSpan.FromHours(15);
});
services.AddAuthorization(config =>
{
var defaultAuthBuilder = new AuthorizationPolicyBuilder("InterclubsCookieAuth");
var defaultAuthPolicy = defaultAuthBuilder
.RequireAuthenticatedUser()
.Build();
config.DefaultPolicy = defaultAuthPolicy;
});
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddSession();
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Enables .Net Core to refresh updated views in browser while debugging
var builder = services.AddControllersWithViews();
builder.AddRazorRuntimeCompilation(options =>
{
var libraryPath = Path.GetFullPath(Path.Combine(Environment.ContentRootPath));
options.FileProviders.Add(new PhysicalFileProvider(libraryPath));
});
}
#endregion
#region Configuration
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler($"/{typeof(HomeController).GetControllerName()}/{nameof(HomeController.Error)}");
app.UseHsts(options => options.MaxAge(days: 365).IncludeSubdomains());
}
app.UseXContentTypeOptions();
app.UseXfo(options => options.SameOrigin());
app.UseXXssProtection(options => options.EnabledWithBlockMode());
app.UseReferrerPolicy(options => options.NoReferrer());
app.UseHttpsRedirection();
var contentTypeProvider = new FileExtensionContentTypeProvider();
if (!contentTypeProvider.Mappings.ContainsKey(".svg"))
{
contentTypeProvider.Mappings.Add(".svg", "image/svg+xml");
}
if (!contentTypeProvider.Mappings.ContainsKey(".woff"))
{
contentTypeProvider.Mappings.Add(".woff", "application/font-woff");
}
if (!contentTypeProvider.Mappings.ContainsKey(".woff2"))
{
contentTypeProvider.Mappings.Add(".woff2", "application/font-woff2");
}
var staticFilesOptions = new StaticFileOptions
{
ContentTypeProvider = contentTypeProvider
};
app.UseStaticFiles(staticFilesOptions);
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: $"{{controller={typeof(ConnectController).GetControllerName()}}}/{{action={nameof(ConnectController.Login)}}}");
});
}
#endregion
}
I solved it: it comes from the TempData.
In .NetCore 3.0 which I'm using, the TempData needs to use Cookies or Session.
I enabled the Session and then the redirect was working again without changing anything to my code !
Hope this will help others.
When a logged in user request the access to an action method where doesnt meet the minimum required role it the error action method returns a null object from IExceptionHandlerPathFeature, it doesnt really change anything if it runs on development,staging or production also I noticed when I tried to use default exception pages the exception page returned was blank, now I had to use custom exception pages to avoid this, I am not sure if this is related somehow
Startup.cs
public class Startup
{
private IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{ options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequiredUniqueChars = 2;
options.Password.RequireNonAlphanumeric = true;
}).AddEntityFrameworkStores<AppDbContext>()/*.AddDefaultTokenProviders()*/;
services.AddDbContextPool<AppDbContext>(options => options.UseSqlServer(_config.GetConnectionString("EmployeeDBConnection")));
services.AddMvc(options=>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddXmlDataContractSerializerFormatters();
//services.AddSingleton<IEmployeeRepository, EmployeeRepository>();
services.AddScoped<IEmployeeRepository, SQLEmployeeRepository>();
services.AddSingleton<IDepartmentRepository, DepartmentRepository>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage(new DeveloperExceptionPageOptions()
{
SourceCodeLineCount = 0,
});
}
else
{
//app.UseStatusCodePagesWithReExecute("/Error/{0}").UseMiddleware<ErrorController>("/Error/{0}");
//app.UseStatusCodePagesWithReExecute("/Error/");
app.UseExceptionHandler("/Error");
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc(route =>
{
route.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});
app.UseStaticFiles();
}
}
ErrorController.cs
public class ErrorController : Controller
{
private readonly IHostingEnvironment hostingEnvironment;
private readonly ILogger<ErrorController> logger;
public ErrorController(IHostingEnvironment _hostingEnvironment, ILogger<ErrorController> _logger)
{
logger = _logger;
hostingEnvironment = _hostingEnvironment;
}
// GET: /<controller>/
[Route("Error/{statusCode}")]
public IActionResult HTTPCodeStatusHandler(int? statusCode)
{
if (statusCode != null && (((int)statusCode) >= int.MinValue && ((int)statusCode) <= int.MaxValue))
{
if (hostingEnvironment.IsDevelopment())
{
return View($"~/Views/shared/error{statusCode}.cshtml");
}
else
{
var statusCodeResult = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCode == 404)
{
ViewBag.ErrorMessage = "Sorry, the page you have requested cannot be found";
if (statusCodeResult != null)
{
//ViewBag.Path = statusCodeResult.OriginalPath;
//ViewBag.QS = statusCodeResult.OriginalQueryString;
logger.LogWarning($"404 Error ocurred.Path :{((statusCodeResult.OriginalPath is "/") ? "/Home": statusCodeResult.OriginalPath )} And Query String {((statusCodeResult.OriginalQueryString is null) ? "/Home":statusCodeResult.OriginalQueryString) }");
}
return View($"~/Views/shared/error{statusCode}.cshtml");
}
}
return View();
}
return Error();
}
[Route("Error")]
[AllowAnonymous]
[HttpGet]
public IActionResult Error()
{
var exceptionDetails = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
logger.LogError($"The path {exceptionDetails.Path} threw andexception {exceptionDetails.Error}");
ViewBag.ExceptionPath = exceptionDetails.Path;
ViewBag.ExceptionMessage = exceptionDetails.Error.Message;
ViewBag.StackTrace = exceptionDetails.Error.StackTrace;
return View("~/Views/shared/Error.cshtml");
}
}
Configure the cookies AccessDenied Path option that solved the issue
services.ConfigureApplicationCookie(options =>
{
options.AccessDeniedPath = new PathString("/Account/AccessDenied");
});
I was working with KOA 2.0 and started to test asp.net core. But can't find a way to handle request/url specific middleware
Say in Koa, with router I can achieve the below:
.post("/api/v1/user", Middleware1, Middleware2, RequestValidationMiddleware, SpecificAction);
.get("/api/v1/user", Middleware1, Middleware2, RequestValidationMiddleware, SpecificAction1);
.post("/api/v1/role", Middleware1, Middleware4, RequestValidationMiddleware2, SpecificAction2);
How to achieve it with asp.net core?
Tried the below:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//app.UseApiLog();
app.Map("/api", ApiLogApps);
app.Map("/exlog", ExceptionLogApps);
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "apilog/{controller}/{action}");
// routes.MapRoute(
// name: "default2",
// template: "exlog/{controller=Home}/{action=Index}/{id:int}");
//});
}
private static void ApiLogApps(IApplicationBuilder app)
{
//app.Run(() => )
app.UseApiLog();
app.UseMvc();
}
And in controller I have
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("test/get/{id}")]
public string Get(int id)
{
return "value";
}
}
But I am lost here.
What I want is, I want to have DataValidation to be handled in a middleware - that forces me to have per url (almost) specific middleware.
PS - I know, model validation can be done in action, but I don't want that.
Thanks in advance for your help :)
To use middlewares like Koa2 , you can configure a sequence of middlewares to build a route :
public IRouter BuildRouter(IApplicationBuilder applicationBuilder)
{
var builder = new RouteBuilder(applicationBuilder);
// use middlewares to configure a route
builder.MapMiddlewareGet("/api/v1/user", appBuilder => {
// your Middleware1
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.Run(SpecificAction);
});
builder.MapMiddlewarePost("/api/v1/user", appBuilder => {
// your Middleware1
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.Run(SpecificAction1);
});
// ....
return builder.Build();
}
and then use RouterMiddleware via UseRouter(router) :
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseRouter(BuildRouter(app));
// ...
app.UseMvc();
}
a screenshot:
[Update]:
To integrate with attribute routing, just add a UseMvc() insteand of Run() as below :
public IRouter BuildRouter(IApplicationBuilder applicationBuilder)
{
var builder = new RouteBuilder(applicationBuilder);
// use middlewares to configure a route
builder.MapMiddlewareGet("/api/v1/user", appBuilder => {
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.UseMvc(); // use a MVC here ...
});
builder.MapMiddlewarePost("/api/v1/user", appBuilder => {
appBuilder.Use(Middleware1);
appBuilder.Use(Middleware2);
appBuilder.Use(RequestValidationMiddleware);
appBuilder.UseMvc();
});
// ....
return builder.Build();
}
Just for a demo , the Middleware1 is a dummy middleware that adds a HttpContext.Items['mw-message1']:
private Func<RequestDelegate, RequestDelegate> Middleware1 = next=> {
return async context =>
{
context.Items["mw-message1"] = "mw1";
await next(context);
};
};
the Controller is a plain controller that will retrieve the HttpContext.Items["mw-messages1"]:
[Route("api/v1/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
public IActionResult Index()
{
var x = (string)HttpContext.Items["mw-message1"];
return new JsonResult(new {
MW1 = x,
Hello= "Hello",
});
}
}
and now , when make a Get request to /api/v1/user , the final response is :
{"mW1":"mw1","hello":"Hello"}
I am using below code in for .net core 3 webapi.
add below in startup.cs configure method to add middleware for specific route
//Middleware to check Authorization key is present in the request header
//Map to all routes
_ = app.UseHeaderKeyAuthorization();
//Map to all routes
_ = app.MapWhen(context => context.Request.Path.StartsWithSegments("/api/v1.0"), appBuilder =>
{
_ = appBuilder.UseHeaderKeyAuthorization();
});
create middleware HeaderKeyAuthorizationMiddleware, sample below
//HeaderKeyAuthorizationMiddleware
public class HeaderKeyAuthorizationMiddleware
{
private readonly RequestDelegate next;
public HeaderKeyAuthorizationMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var authHeader = httpContext.Request.Headers[ApiConstants.AuthHeaderName];
//check authHeader logic
if (!string.IsNullOrEmpty(authHeader))
{
await next.Invoke(httpContext);
return;
}
//Reject request if there is no authorization header or if it is not valid
httpContext.Response.StatusCode = 401;
await httpContext.Response.WriteAsync("Unauthorized");
}
}
//Middleware extension to register middleware
public static class HeaderKeyAuthorizationMiddlewareExtension
{
public static IApplicationBuilder UseHeaderKeyAuthorization(this IApplicationBuilder app)
{
if (app == null)
{
throw new ArgumentNullException(nameof(app));
}
return app.UseMiddleware<HeaderKeyAuthorizationMiddleware>();
}
}