ASP.NET Web Api 2 Custom HttpResponseMessage - asp.net

I created a custom Result I use in the Web API Controller actions where I return a custom async Task<IHttpActionResult>.
public class CustomResult<T> : NegotiatedContentResult<T>
{
public CustomResult(HttpStatusCode statusCode, T content, ApiController controller)
: base(statusCode, content, controller)
{
}
public CustomResult(HttpStatusCode statusCode, T content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
: base(statusCode, content, contentNegotiator, request, formatters) { }
public override async Task<HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.ExecuteAsync(cancellationToken);
return response;
}
}
And basically in my action I return it like this:
public async Task<IHttpActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid)
{
return new CustomResult<string>(HttpStatusCode.BadRequest,"Model is invalid", this);
}
else
{
return new CustomResult<string>(HttpStatusCode.Ok,"Model is valid", this);
}
}
The problem is the custom message I want to return. It doesn't work! If the model is invalid I always get the 400 Bad Request and the custom message: "The remote server returned the following error while establishing a connection - 'Bad Request', instead of getting 400 Bad Request and my custom message Model is invalid.
This however works when I return 200 OK.
Is there something I am doing wrong?

Try to set
<system.webServer>
<httpErrors existingResponse="PassThrough"/>
</system.webServer>
in web.config. PassThrough option - leaves the response untouched if an existing response exists. (more about httperrors)

Related

accept xml as request body in asp.net 6 rest api

I need to accept xml as request body
Here is my controller
[HttpPost]
[Route("UpdateLeaveBalance")]
[ProducesResponseType(typeof(RootLeaveBalanceDto), (int)HttpStatusCode.OK)]
public async Task<IActionResult> CreateOrUpdate([FromBody] RootLeaveBalanceDto model)
{
var result = await _leaveBalanceService.SetLeaveBalance(model);
return OkResult(result);
}
here is the program.cs
services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(GlobalModelStateValidatorAttribute));
}).AddXmlDataContractSerializerFormatters();
I tried using this code i gave but when i set debuger i got no data but the post request gives 200

Is it possible to call synchronous http post request using ASP.net?

I have a scenario where http POST request execute, call another get request and return response of get request. Here is my code
public class EmployeeController : ControllerBase
{
private readonly IBusControl _bus;
public EmployeeController(IBusControl bus)
{
_bus = bus;
}
[HttpPost]
public async Task<IActionResult> Emp(EmployeeModel employee)
{
Uri uri = new Uri("rabbitmq://localhost/ret_eligibility");
var endPoint = await _bus.GetSendEndpoint(uri);
await endPoint.Send(employee);
return Ok("Success");
}
[HttpGet]
[Route("getRetFund")]
public IActionResult fund()
{
Fund fund = RetFundConsumer.fund;
return Ok(fund.retfund);
}
}
I want to call getRetFund request in POST request method, So that when employee data is sent to queue using postman, it call second service which consume message and send response back. This response will be shown then in console.
I also have tried the following POST method.
[HttpPost]
public async Task<IActionResult> Emp(EmployeeModel employee)
{
Uri uri = new Uri("rabbitmq://localhost/ret_eligibility");
var endPoint = await _bus.GetSendEndpoint(uri);
await endPoint.Send(employee);
//return Ok("Success");
Fund fund = RetFundConsumer.fund;
return Ok("your retirement fund is " + fund.retfund);
}
But this throw null Exception as it call second service before executing POST request. The response would be greatly appreciated.
This would never work. You need to spend time about both Web API request handling scope and MassTransit message handling scope.
In short, both Web API and MassTransit message handling is scoped to one message. There is no way you can consume a response message, somehow magically keeping the HTTP session open. The consumer gets disposed when it finishes handling a message.
You can do it, though, but you need to use the MassTransit request/response feature.
public class EmployeeController : ControllerBase
{
private readonly IRequestClient<EmployeeModel> _client;
public EmployeeController(IClientFactory clientFactory)
=> _client = clientFactory.CreateRequestClient<EmployeeModel>(
new Uri("rabbitmq://localhost/ret_eligibility"));
[HttpPost]
public async Task<IActionResult> Emp(EmployeeModel employee)
{
var response = await _client.GetResponse<Fund>(employee);
return Ok("your retirement fund is " + fund.retfund);
}
}
Of course, you need to change your consumer accordingly to send a message back. Check the documentation referenced above for the details.

Delete request fails with 415 Unsupported Media Type

I am working on a React application that uses MobX, and have encountered a problem with implementing the Delete HTTP request. All the other requests work fine.
MobX store action:
try {
await agent.Artworks.delete(id);
this.artworkRegistry.delete(id);
} catch (error) {
console.log(error);
}
};
Agent methods:
del: (url: string) => axios.delete(url).then(responseBody)
delete: (id: string) => requests.del(`/artworks/${id}`)
Command handler:
{
public class Delete
{
public class Command : IRequest
{
public Guid Id { get; set; }
}
public class Handler : IRequestHandler<Command>
{
private readonly DataContext _context;
public Handler(DataContext context)
{
_context = context;
}
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
var artwork = await _context.Artworks.FindAsync(request.Id);
if (artwork == null)
throw new Exception("Could not find artwork");
_context.Remove(artwork);
var success = await _context.SaveChangesAsync() > 0;
if (success) return Unit.Value;
throw new Exception("Problem saving changes");
}
}
}
}
The console gives me the following error:
Object { data: {…}, status: 415, statusText: "Unsupported Media Type", headers: {…}, config: {…}, request: XMLHttpRequest }
What am I missing?
The request that you are sending is malformed. You are getting a 415 response error which is: 415 Unsupported Media Type
That means that server is refusing to process the request because it doesn't recognize the format the request is in. So there is also a possibility that your server is misconfigured. Try sending the request outside your app (via terminal using curl) and see what kind of response you get.
You can read more on MDN 415 Unsupported Media Type

How to pass header in Azure endpoint..?

I am using Azure API , URL getting below error please help on this issue. please share codesnip, how to change in web.config and endpoints.
The HTTP request is unauthorized with client authentication scheme
'Anonymous'. The authentication header received from the server was
'AzureApiManagementKey
realm="https:/azure.azure-api.net/MethodName",name="Ocp-Apim-Subscription-Key",type="header"'.
I know this is a very old question still, my answer would help someone faces the same issue.
The solution is to create a custom endpoint behavior where you add a custom message handler to the binding parameters.
In the custom message handler, please add your request headers. After this, use any of the binding technique (like basichttpsbinding or NetHttpsBinding) with security mode as "Transport" and MessageEncoding as "Text" for creating soap client object. Add custom endpoint behavior to the soap client.
public class CustomEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
bindingParameters.Add(new Func<HttpClientHandler, HttpMessageHandler>(x =>
{
return new CustomMessageHandler(x);
}));
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
public class CustomMessageHandler : DelegatingHandler
{
public CustomMessageHandler(HttpClientHandler handler)
{
InnerHandler = handler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Headers.Add("xxxx", "abcde");
return base.SendAsync(request, cancellationToken);
}
}
The console app to consume the service.
static async Task Main(string[] args)
{
var client = GetSOAPClient();
try
{
var result = await client.MyOperation().ConfigureAwait(false);
if(result.Body != null && result.Body.status == "Success")
{
Console.WriteLine(result.Body.myValue);
}
}
catch (Exception ex)
{
Console.WriteLine(ex?.Message);
}
Console.ReadKey();
}
static MyServiceClient GetSOAPClient()
{
NetHttpsBinding binding = new NetHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.MessageEncoding = NetHttpMessageEncoding.Text;
EndpointAddress ea = new EndpointAddress(new Uri("https://myazureurl"));
var client = new MyServiceClient(binding, ea);
client.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior());
return client;
}
}
This is complaining that your Subscription key is wrong. If you check the response body, it will give you a readable message of what the real problem is. Double check you are entering the correct subscription key for your Azure API access.
You get your subscription key from the Developer Portal under your profile menu. You can see an example of the subscription key being used in this article under the section "Call an operation from the developer portal": https://learn.microsoft.com/en-us/azure/api-management/api-management-get-started
Also, the 'The HTTP request is unauthorized with client authentication scheme 'Anonymous'.' part of the message is a red herring and a separate problem with how responses work.

Getting User Id in Web Api handler when using Cachecow

I have a MVC Web Api project and am logging all requests and responses using a MessageHandler. When an api request comes in, the bearer token in the header lets Asp.Net do its thing and authenticates that user. The message handler therefore knows who the user is and we write that to a log file.
Now, to speed up things I'm caching with Cachecow. So I've added the cachecow handler after the MessageHandler and when a second request comes in, from a caching point of view everything works fine. The controller code is never hit and the response is returned from the cache.
However, the MessageHandler does not have a value for the User.Identity so I cannot tell who made the request.
I need to log all requests and identify who made them even when the code in the controllers is not hit.
I think one workaround is to force the api requests to pass the bearer token and user id in the header. That way I can check the user id claim and use that to log who made the request.
protected override async Task OutgoingMessageAsync(string correlationId, string requestInfo, byte[] message, string responseTimeMilliseconds)
{
await Task.Run(() =>
Debug.WriteLine(string.Format("{0} - Response: {1}\r\n{2}", correlationId, requestInfo, Encoding.UTF8.GetString(message))));
);
}
User identity is null when getting response from cache.
?HttpContext.Current.User.Identity
{System.Security.Claims.ClaimsIdentity}
[System.Security.Claims.ClaimsIdentity]: {System.Security.Claims.ClaimsIdentity}
AuthenticationType: null
IsAuthenticated: false
Name: null
Any ideas?
In authentication process, set object:
System.Threading.Thread.CurrentPrincipal = YourUserInformationObject;
This object need implement "System.Security.Principal.IPrincipal" Example
public class YourUserInformation : IPrincipal
{
public Int32 Id { get; set; }
public String NameUser { get; set; }
public IIdentity Identity { get; private set; }
public YourUserInformation()
{
this.Identity = new GenericIdentity(NameUser ?? "");
}
public bool IsInRole(string role) { return false; }
}
In authentication process you save object in System.Threading.Thread.CurrentPrincipal
public void Authentication(AuthorizationContext filterContext)
{
YourUserInformation user = YourMethodGetUserLogin();
System.Threading.Thread.CurrentPrincipal = user ;
}
Well you should create HttpContext from Request and there you will be able to use User.Identity object:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var context = ((HttpContextBase)request.Properties["MS_HttpContext"]);
var uname = username = context.User.Identity.Name;
var response = await base.SendAsync(request, cancellationToken);
return response;
}
Also check this article: http://arcware.net/logging-web-api-requests/
Hoope this help!
try get in
System.Threading.Thread.CurrentPrincipal

Resources