How to intercept a 404 Not Found using the OWIN pipeline - asp.net-mvc

I have another question to do with Web-API and OWIN. I am "playing" with it, trying to learn about it, and I wanted to see if I could intercept a 404 on the "way back" from the web api.
So, I have the following in my Startup..
app.Use(async (environment, next) =>
{
Debug.WriteLine(environment.Request.Uri);
await next();
Debug.WriteLine(environment.Response.StatusCode);
});
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
I then do a GET (in a browser) using an invalid URI so that I get a 404 result. I expected to see this as the status code written out in the Debug.WriteLine(environment.Response.StatusCode)
However, all I see (in dev studio output window , as I am running IIS express) is
http://localhost:55905/myresource
http://localhost:55905/myresource
200
200
I really expected to the the 404 in there.
Does anyone know why we don't see the 404 coming back?
I have looked through the Response, and cannot see it anywhere.
Thanks in advance for any help!

Is /myresource a valid webapi route?
I think (but I'm not sure) your request is handled by IIS directly ignoring the owin-pipeline. But I don't know why its responding with a 200.
You can test it really easy.
Assuming your code and the following configuration:
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
}
}
And modified your Startup class a little:
app.Use(async (environment, next) => {
Debug.WriteLine(environment.Request.Uri);
environment.Response.OnSendingHeaders(_ => {
var resp = ((IOwinResponse) _);
Debug.WriteLine("Headers are send!: {0}", resp.StatusCode);
resp.Headers.Add("X-MyTag", new[] {"Nice value!"});
}, environment.Response);
await next();
Debug.WriteLine(environment.Response.StatusCode);
});
Sample controller:
public class ValuesController : ApiController {
// GET api/<controller>
public IEnumerable<string> Get() {
return new string[] { "value1", "value2" };
}
}
Now the OWIN Pipeline should return in EACH request a custom header X-MyTag.
I'm using Fiddler to inspect my request.
A request to http://localhost:13543/ responds without my header. So it isn't served by the owin pipeline.
On the other hand a request to http://localhost:13543/api/Values responds with a 200 and my custom header.
An (invalid) request to http://localhost:13543/api/Values1 responds with 404 including my custom header AND you can see this 404 in your output console.

Related

How to add CORS middleware in shelf with router?

I am new to server side programming with dart. I made a simple API server with a number of get routes. I am handling this as follow,
Router router = Router();
router.get('/', checkSTATUS);
router.get('/login/<user>/<pass>', (Request request, String user, String pass) async {
id = 0;
// stuff
return Response.ok(json.encode({"status":"found","id":id}));
});
router.get('/update', (Request request) async {
//stuff
return Response.ok(json.encode({"status": "updated", "data": updated}));
});
//for any other requests
router.all('/<ignored|.*>', (Request request) {
return Response.notFound(json.encode('Page not found'));
});
final server = await serve(
router,
InternetAddress.anyIPv4,
8080,
);
I can access these routes using postman but making requests using flutter web results in error. I searched and found out that this may be CORS related. But how do I add the CORS headers without disrupting the entire code.
Please refer this document. https://pub.dev/packages/shelf_cors_headers.
Install this package

How to correctly configure Web-API2 Routes to accept strings that go to an object?

I have a .NET project that has a Web API portion to it which should be accepting requests externally. The action accepts an object which is then used further on. The problem is when testing with postman app, the action is hit but variables are not passed.
Here is an example of my URL in postman: http://localhost:12345/api/login/postlogin?Username=un&Password=pw
I have tried using [frombody], this would work only if I am receiving a single string. My application will be utilizing lots of data passing back and forth. I have also tried multiple solutions on StackOverflow including [FromUri]. The post is still null.
WebAPi.Config snippet:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Action within Controller:
// POST: api/postLogin/
[AllowAnonymous]
[System.Web.Http.HttpPost, System.Web.Http.Route("postlogin")]
public async Task<IHttpActionResult> PostLogin(LoginDTO login)
{
}
The expected result as stated early is to receive variables as an object then use them within the action.
Your configuration for Routing is correct. You should use [FromBody] attribute to the parameter, because this is a POST request.
you should never use GET request to do authentication!
public async Task<IHttpActionResult> PostLogin([FromBody]LoginDTO login)

Is it possible to config multiple routes with ODATA

I've created a project containing both MVC and WebAPI.
There's a MVC controller named HomeController which containing only one action named Index.
Also, there's a API controller named ValuesController.
Everything works fine without OData, I can access to both http://localhost/Home/Index and http://localhost/api/Values successfully.
However, after I changed some code to support OData, I'm failed to access to http://localhost/Home/Index. Below is the related code:
//startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddDbContext<ProductsContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDb");
});
//Adding OData middleware.
services.AddOData();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider provider){
if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}
//Adding Model class to OData
var builder = new ODataConventionModelBuilder(provider);
builder.EntitySet<ValuesEntity>("Values");
builder.EntityType<ValuesEntity>().Filter(QueryOptionSetting.Allowed).OrderBy(QueryOptionSetting.Allowed);
//Enabling OData routing.
app.UseMvc(routebuilder =>
{
routebuilder.MapODataServiceRoute("odata", "api", builder.GetEdmModel());
routebuilder.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
As you can see, there're multiple routes, but the default route seems never get used.
I can still access to the http://localhost/api/Values, but If I access to the http://localhost/Home/Index, the page will show me the error:
An unhandled exception occurred while processing the request.
ArgumentNullException: Value cannot be null.
Parameter name: routeName
Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.CreateRequestScope(HttpRequest request, string routeName)

ASPNET 5: How to receive request parameter as raw content no matter what the Content-Type header is set to?

I'm building an API where the client can send me a blob of data and I save it somewhere for retrieval later. I don't care what the content-type is. I just want to get the raw data every time, no matter what they set Content-Type to. I know this can be achieved in older versions of ASPNET by accessing the Request object, but this does not seem possible with ASPNET 5, nor would I want to do this because it would make unit testing impossible (Request is not dependency injected).
I've seen some mentions of the IInputFormatter and IOutputFormatter interfaces, but those seem to attach to a specific Content-Type. I think I'm looking for something that's more like the [FromBody] attribute, but that gives me raw output. Something like [RawBody]. I've done quite a bit of searching and can't seem to find any simple solutions for this.
you can create CustomAttribute and read Request.InputStream with StreamReader Save stream data where ever you want then reset InputStream position to 0
httpContext.Request.InputStream.Position = 0;
I used it in Custom AuthorizeAttribute but you can use use Custom ActionFilter and use Request from filterContext you can google for "Custom Attribute in MVC c#" you can also do that in ActionResult.
If you are still looking for solution to get Request Object here is the solution
Create MessageHandler
public class MessageHandler1 : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpContextWrapper context = (HttpContextWrapper)request.Properties.ElementAt(0).Value;
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
add Entry to WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.MessageHandlers.Add(new MessageHandler1());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Now you can access row Request in MessageHandler1

Implementing Message Handlers in MVC 6

I have current API (web api 2) project that has a number of message handlers in use, some run for every request (checking to make sure the request is https and the request is coming from an authorised client) and some that run on specific routes (checking for the existence of a security token).
Now my question is how do I replicate this functionality in MVC 6, my current understanding is that it should be done through the use of middleware but I've not found an example that allows me to inspect the headers of the incoming request and should they not be what they are supposed to be return the appropriate http response code.
Middleware is definitely the right option to solve what you're looking to solve. I wrote a decent explanation about using/writing middlware here: ASP.NET MVC 6 handling errors based on HTTP status code
To specifically answer how to inspect headers here's an example:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
if (!string.Equals(context.Request.Headers["myheader"], "somevalue", StringComparison.Ordinal))
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("Invalid headers");
}
else
{
await next();
}
});
}
}

Resources