How to make a FromHeader parameter optional in minimal API - c#-6.0

I have a minimal API working in C#6, but want to make one of the FromHeader parameters optional. This is the current code:
public static void MapGetInstallationByIngressEndpoint(this WebApplication app) =>
app.MapPost(Url, async (
[FromBody] GetInstallationByIngressRequest getInstallationByIngressRequest,
[FromHeader(Name = Constants.AssetIdHeader)]
Guid accountId,
[FromHeader(Name = Constants.CorrIdHeader)]
Guid correlationId,
[FromServices] IRequestHandler<GetInstallationByIngressRequest, InstallationQueryResult> requestHandler,
[FromServices] IValidator<GetInstallationByIngressRequest> requestValidator,
CancellationToken cancellationToken) =>
{
and I want to make accountId optional. I've tried making it nullable (Guid? accountId), but no luck. Is it possible?

Related

How to handle exception in IAuthenticationFilter interface?

I have created custom Authentication class using IAuthenticationFilter interface.
instead of using ChallengeAsync I have directly throw exception how to handle it ?
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
if (authorization == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest,"FAIL"));
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
//var challenge = new AuthenticationHeaderValue("Basic");
//context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result);
//return Task.FromResult(0);
}
but how to handle exception throw?
From documentation: The HttpResponseException type is a special case, because it is designed specifically for returning an HTTP response. So you do not need to handle this exception. From ChallengeAsync code, I suppose you want to add authentication header to response if request was unauthorized. You can implement it like
public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
var challenge = new AuthenticationHeaderValue("Basic");
var response = request.CreateResponse(HttpStatusCode.BadRequest, "FAIL");
response.Headers.WwwAuthenticate.Add(challenge);
throw new HttpResponseException(response);
}

Trying to use IPipelineBehavior with ASP.NET Core - get System.InvalidCastException

I'm using Mediatr 3's new features for Pipeline Behaviors. Problem is, when I wire them into Mediatr, exceptions (System.InvalidCastException) get thrown for every .Send() call. Handlers get called fine, but when its time for the pipeline behaviors to get called, it fails.
Here's my setup:
services.AddScoped<SingleInstanceFactory>(p => t => p.GetRequiredService(t));
services.AddScoped<MultiInstanceFactory>(p => t => GetRequiredServices(p,t));
services.AddScoped(typeof( IPipelineBehavior<, >), typeof(AddSessionBehavior<, >));
services.AddMediatR();
And my Behavior:
public class AddSessionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
IHttpContextAccessor Accessor;
public AddSessionBehavior(IHttpContextAccessor anAccessor)
{
this.Accessor = anAccessor;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
return response;
}
}
When I send my first message through mediator, I get:
System.InvalidCastException occurred
HResult=0x80004002
Message=Object cannot be stored in an array of this type.
Source=<Cannot evaluate the exception source>
StackTrace:
at System.Array.InternalSetValue(Void* target, Object value)
at System.Array.SetValue(Object value, Int32[] indices)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitClosedIEnumerable(ClosedIEnumerableCallSite closedIEnumerableCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitTransient(TransientCallSite transientCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at MediatR.ServiceCollectionExtensions.GetRequiredServices(IServiceProvider provider, Type serviceType)
at MediatR.Internal.RequestHandlerImpl`2.GetPipeline(TRequest request, RequestHandlerDelegate`1 invokeHandler, MultiInstanceFactory factory)
at MediatR.Internal.RequestHandlerImpl`2.Handle(IRequest`1 request, CancellationToken cancellationToken, SingleInstanceFactory singleFactory, MultiInstanceFactory multiFactory)
at MediatR.Mediator.Send[TResponse](IRequest`1 request, CancellationToken cancellationToken)
at Merlin.Web.Controllers.CourseController.Add(CourseAddVM model)
If I comment out the wiring for my behavior, my handlers get called fine. And the rest of the application seems to work.
What have I done wrong?
I figured it out.
Turns out that somewhere along the way an internal class with the same name as my behavior was created in a different namespace in my application. Probably the result of a "Generate Class definition".
Removing the generated class cleared up the issue.

Web API - Get RouteData, Action or Controller in DelegationHandler from HttpRequestMessage

I am having a difficulty to get route data, action or controller in DelegatingHandler.
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var routeData = request.GetRouteData();
in this example routeData is always null. Is there any way how to get the context of the Web API controllers and thus actions so I could tell what action the URL is trying to invoke?

Breeze webapi controller 'cannot support querying' over DbSet error

I have setup very similar to breeze sample application which comes in sample nuget. This is the code of my api controller:
[JsonFormatter, ODataActionFilter]
public class WorkOrdersController : ApiController
{
readonly EFContextProvider<WorkOrdersContext> _contextProvider =
new EFContextProvider<WorkOrdersContext>();
public WorkOrdersController()
{
// I was thinking this may be the cause of the issue
this._contextProvider.Context.Configuration.ProxyCreationEnabled = false;
}
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<WorkOrder> WorkOrders()
{
return _contextProvider.Context.WorkOrders;
}
}
The problem I'm having is when I try to perform query over WorkOrders action, I get 500 - Internal server error, and this is the payload of response:
{"$id":"1","$type":"System.Web.Http.HttpError, System.Web.Http","Message":"An error has occurred.","ExceptionMessage":"The action 'WorkOrders' on controller 'WorkOrders' with return type 'System.Collections.Generic.List`1[[WorkOrders.Domain.Models.WorkOrder, WorkOrders.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' cannot support querying. Ensure the type of the returned content is IEnumerable, IQueryable, or a generic form of either interface.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.QueryableAttribute.ValidateReturnType(Type responseContentType, HttpActionDescriptor actionDescriptor)\r\n at System.Web.Http.QueryableAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)\r\n at System.Web.Http.Tracing.Tracers.ActionFilterAttributeTracer.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<>c__DisplayClass2.<System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync>b__0(HttpResponseMessage response)\r\n at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass41`2.<Then>b__40(Task`1 t)\r\n at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)"}
WorkOrders is Dbset on context:
public DbSet<WorkOrder> WorkOrders { get; set; }
I have also tried explicitly casting it to IQueryable, with no change:
[HttpGet]
public IQueryable<WorkOrder> WorkOrders()
{
return (IQueryable<WorkOrder>)_contextProvider.Context.WorkOrders;
}
The only thing that works for me is:
[HttpGet]
public IEnumerable WorkOrders()
{
return _contextProvider.Context.WorkOrders.AsEnumerable();
}
This, however causes another problem for me on the client side, described in this question.
Just a guess here, but can you try using the latest breeze (v 0.82.1) with the following attribute.
[BreezeController]
instead of these
[JsonFormatter, ODataActionFilter]
The new [BreezeController] attribute is a complete replacement for the other two and avoids some other issues.

How to get HttpRequestMessage instead of HttpContext.Current in WebApi

I have found several sources that say that you should not use HttpContext.Current in WebApi but none that say how you should handle those cases where we used to use HttpContext.Current.
For example, I have a LinkProvider class that creates links for an object. (simplified to stay on topic).
public abstract class LinkProvider<T> : ILinkProvider<T>
{
protected ILink CreateLink(string linkRelation, string routeName, RouteValueDictionary routeValues)
{
var context = System.Web.HttpContext.Current.Request.RequestContext;
var urlHelper = new System.Web.Mvc.UrlHelper(context);
var url = string.Format("{0}{1}", context.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority), urlHelper.RouteUrl(routeName, routeValues));
///...
return new Link(linkRelation, url);
}
}
and this class is used by a MediaTypeFormatter.
This class is expected to build a link using the same host that came from the original request and leveraging any route values that were on the original request.
But... how do I get a hold of the HttpRequestMessage? This will be encapsulated by a MediaTypeFormatter - but it doesn't have one either.
There must be an easy way to get hold of the HttpRequestMessage - what am I overlooking?
thanks
Jon
I ended up creating the following base Formatter which exposes the request, now I will be able to pass it along to the LinkProvider.
public class JsonMediaTypeFormatterBase : JsonMediaTypeFormatter
{
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
Request = request;
return base.GetPerRequestFormatterInstance(type, request, mediaType);
}
protected HttpRequestMessage Request
{
get;
set;
}
}

Resources