1

I have a unique situation where I need to get the DepartmentId from either the [FromRoute] or [FromQuery] or [FromBody]. This is weird as I cannot break my public api action contracts and cannot do much about it. Also I cannot alter the business contracts which is called inside from the controller, so that I cannot pass the DepartmentId down the pipeline.

I see that I can inject the IHttpContextAccessor and get the IHttpContextAccessor.HttpContext. I was able to get the DepartmentId for [FromQuery] as below:

request.QueryString.Value.Replace("?", "")
                            .Split("&")
                            .FirstOrDefault(x => x.Contains("departmentId"))
                            ?.Split("=")[1];

I am getting it [FromRoute] parameter as below;

var departmentId = 0;
var match = Regex.Match(request.Path, "Department/\\d+");
if (match.Success && match.Groups.Any())
{
    int.TryParse(match.Groups[0].Value.Replace("Department/", ""), out departmentId);
} 

I do not know how I can get the DepartmentId from the [FromBody] complex object. But I do know that all the request objects used in the [HttpPost] is inheriting from the Department class which has a DepartmentId.

Any helps are appreciated....

3
  • Request.InputStream contains the body of the HTTP request; accessible as a Stream Commented May 10, 2018 at 19:02
  • I don't see the InputStream inside Request. I am using .net core if you have not noticed that. Did you mean IHttpContextAccessor.HttpContext.Request? Commented May 10, 2018 at 20:48
  • You could retrieve the DepartmentId from a middleware and then set a property of a scoped lifetime registered caching class. Then you wouldn't need to use HttpContextAccessor. As a side comment - using HttpContextAccessor carries performance costs, it's good to use other means to workaround it. Commented May 12, 2018 at 12:04

1 Answer 1

2

Using middleware I'd do something like this:

public class EstablishDepartmentMiddleware
{
    private RequestDelegate _next;

    public EstablishDepartmentMiddleware(RequestDelegate next)
    {
        this._next = next;            
    }

    public async Task InvokeAsync(HttpContext context, IDepartmentContext departmentContext)
    {            
        await TryGetDepartmentFromBody(context, departmentContext);
        // TryGetFromQuery
        // TryGetFromRoute
        await _next(context);
    }

    private static async Task TryGetDepartmentFromBody(HttpContext context, IDepartmentContext departmentContext)
    {
        using (var sr = new StreamReader(context.Request.Body))
        {
            var bodyText = await sr.ReadToEndAsync();
            var department = JsonConvert.DeserializeObject<Department>(bodyText);
            if (department != null)
            {
                departmentContext.DepartmentId = department.DepartmentId;
            }
        }
    }
}

Here are other classes:

public interface IDepartmentContext
{
    int DepartmentId { get; set; }
}

public class DepartmentContext : IDepartmentContext
{
    public int DepartmentId { get; set; }
}

public class Department
{
    public int DepartmentId { get; set; }
}

Here's what goes into the startup class:

app.UseMiddleware<EstablishDepartmentMiddleware>();

You can do something similar with action filters as well - middleware will work with all requests which arrive.

Obviously you can take the code above and using IHttpContextAccessor the same way get the DepartmentId from Body. Bear in mind - you might be leaking your infrastructure to your business layer - if you use the accessor in your business classes.

Sign up to request clarification or add additional context in comments.

3 Comments

Right now I am using the IHttpContextAccessor as I am tight on a deadline. But I will let my manager know about this one. Marking this as the answer for now. Thanks...
I got it working by following your instructions except in the post. The request Body becomes NULL after it is read. What can we do for that?
My bad - most probably it's because StreamReader is in a using() statement, which disposes the stream reader when it's getting out of scope. When SR disposes then the underlying stream is getting disposed as well. You can try removing the using statement and possibly also rewinding the stream as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.