Closing an async Response - asp.net-core-mvc

I'm trying to close the current response but nothing happens when I try HttpContext.Response.Body.Close() and Response.End() does not exist.
The reason I'm trying to achieve this is because of legacy validator functions that write an error and close the response, or at least stopping the parent WebAPI method.
Example:
private async Task Register_v2()
{
//Read JSON to object
UserRegisterRequest userRegisterRequest = Request.ReadBody().FromJson<UserRegisterRequest>();
//Validate object (legacy static method with a lot of logic)
//Validate() should end the response if object not validated
userRegisterRequest.Validate(isJson: true, isThrowHttpError: true);
//Code still reaches here and request does not close
string test = "hey I'm alive";
}
Can I workaround this with middleware somehow?
Thanks

There are two ways to terminate the Request pipeline.
Use app.Run in Startup.Configure
Do not invoke _next(context) in Middleware.InvokeAsync
For your scenario, you could try second option by determining whether to invoke _next(context).
public class FirstMiddleware
{
private readonly RequestDelegate _next;
public FirstMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync($"This is { GetType().Name }");
//decide whether to invoke line below based on your business logic
//await _next(context);
bool isValid = userRegisterRequest.Validate(isJson: true, isThrowHttpError: true);
//change userRegisterRequest.Validate to reutrn whether the model is valid
if(!isValid)
{
await context.Response.WriteAsync($"Model is not valid");
}
else
{
await _next(context);
}
}
}

Related

Call several different JavaScript within AjaxLink one after the other

When I click on an AjaxLink, I would like to have a validation via JavaScript on the client side first (because the LocalStorage is queried) and then depending on the result, further JavaScript calls are made. How can i achieve this?
In a pseudo code it would look like this:
new AjaxLink<>("myId", myModel) {
#Override
public void onClick(AjaxRequestTarget target) {
boolean isCounterValid = target.appendJavaScript(checkCounter()); // i know that this is not possible, therefore pseudo code
if(isCounterValid) {
target.appendJavaScript(someOtherJavaScript());
}
else {
target.appendJavaScript(anotherJavaScript());
}
}
private String checkCounter() {
return "var count = window.localStorage.getItem('myCounter'); return count !== 1;";
}
private String someOtherJavaScript() {
return "change something";
}
private String anotherJavaScript() {
return "change other thing";
}
};
You need to send extra request parameters with the Ajax call when the link is clicked. For that you should override updateAjaxAttributes(AjaxRequestAttributes attributes) method of AjaxLink:
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.getDynamicExtraParameters().add("var count = window.localStorage.getItem('myCounter'); return [{\"name\":\"count\", \"value\": count}]");
}
This way inside AjaxLink#onClick() you can read the count via:
int count = getRequest().getRequestParameters().getParameterValue("count").toInt();
AJAX components and behaviors can customize AJAX attributes overriding updateAjaxAttributes and using a custom implementation of AjaxCallListener which exposes different method to hook into the AJAX request cycle. In you case you could use AjaxCallListener#getBeforeSendHandler.
For a full introduction to this topic (with examples) see user guide:
https://ci.apache.org/projects/wicket/guide/8.x/single.html#_ajax_request_attributes_and_call_listeners

invalid_grant of OAuthAuthorizationServerProvider

I'm working on writing fully customized ASP.NET Identity for my WebAPi.
I have rewritten my own derived OAuthAuthorizationServerProvider in this way:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Check User availability ...
//ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
// if i couldn't found user in my DataBase ...
//if (user == null)
//{
//context.SetError("invalid_grant", "The user name or password is incorrect.");
// return;
//}
context.Validated();
}
}
GrantResourceOwnerCredentials just returns an invalid_grant error for each calls. i want to handle it but, i don't know how.
ValidateClientAuthentication is where you would do your authentication checks and this is where you throw errors if anything doesn't match.
move your code there and do the checks before you call context.Validated(). You only call the Validate method once you make sure everything is validated correctly.
here is an example of such an implementation I did a while back:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId;
string clientSecret;
//first try to get the client details from the Authorization Basic header
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
//no details in the Authorization Header so try to find matching post values
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(clientSecret))
{
context.SetError("client_not_authorized", "invalid client details");
return Task.FromResult<object>(null);
}
var dataLayer = new RepoManager(new DataLayerDapper()).DataLayer;
var audienceDto = dataLayer.GetAudience(clientId);
if (audienceDto == null || !clientSecret.Equals(audienceDto.Secret))
{
context.SetError("unauthorized_client", "unauthorized client");
return Task.FromResult<object>(null);
}
context.Validated();
return Task.FromResult<object>(null);
}
Notice how the checks happen in order and certain errors are raised with some appropriate errors.
This code takes a client id and client secret from an authorization header but you can easily drop all that and replace it with your own checks and database calls.
The important part is that this is where you deal with stuff like this and this is where you set the errors so your clients know what's going on.
GrantResourceOwnerCredentials this is where you get once the call is properly authenticated, at which point you can start creating tokens, adding claims and creating the authentication ticket. This method does not get hit if the previous one fails to authenticate the request.
Here is a working example:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim("clientID", context.ClientId));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"audience", context.ClientId
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
return Task.FromResult<object>(null);
}
Now, if you get an invalid grant error that usually happens because you either didn't set up the grant_type in your initial call or you set up the wrong value.
in my case I had to setup this:
"grant_type", "password"

Custom Async Action Filter for Web API 2

I have a web api to consume the data coming from android mobile. This web api will consume the multi part file from along with the form data the web api request. I followed this article to archive.
[CustAuthAsync]
public async Task<HttpResponseMessage> SaveEHSInspectionData()
{
try
{
string root = HttpContext.Current.Server.MapPath("~/App_Data");
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(root);
//do stuff
var res = await Request.Content.ReadAsMultipartAsync(provider);
// DO SOME STUFF
}
catch (Exception exp)
{
}
return Request.CreateResponse(HttpStatusCode.OK, result);
}
I wanted to do the custom access validation for this web api, so implemented a filter to validate the request.
I have the filter like below
public class CustAuthAsyncAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
InternalOnExecutingAsync(actionContext);
}
}
The internal method like this
protected void InternalOnExecutingAsync(HttpActionContext actionContext)
{
var authValue = actionContext.Request.Headers;
if (authValue.Contains("CustomAccessToken"))
{
string token = authValue.GetValues("CustomAccessToken").First();
var result = // doing some decription
if (result != null)
{
bool validationResult = // validation with database
if (!validationResult)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Invalid token" };
}
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Invalid token" };
}
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Unauthorized Request" };
}
These implementations are working fine in API Client Tools (Example: Postman) if the validation passes, allows the request to the method.
Postman Response screen shot
This is not working in mobile app, Saying the response message as Unauthorized Access. and not allowing the request to the method even the custom access validations are passed.
FYI : This method is working fine in mobile without filter
Help me to get this works in mobile app also.
Thanks in advance.
Your using the wrong type of filter to manage access. You should use an authorization filter. Besides you can't have an async method to authorize. You have to make the calling client wait for clearance. This may cause the side effects you're experiencing.
I'm not sure this has any to do with fact that it's a mobile application, however the authorization phase ir prior to the processing of the request. Verify that your are not using any other form of authorization in your project.
You should implement an authorization filter by inheriting AuthorizeAttribute and overriding IsAuthorized(HttpActionContext actionContext) method:
public class CustAuthAsync : AuthorizeAttribute
{
public CustAuthAsync()
{
///Some initialization if required. Otherwise, not necessary to declare the constructor..
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var authValue = actionContext.Request.Headers;
if (authValue.Contains("CustomAccessToken"))
{
string token = authValue.GetValues("CustomAccessToken").First();
var result = // doing some decription
if (result != null)
{
return //database validation
}
else
{
return false;
//No need to create special unauthorized response. You should not hint the reason at this point. You can do this in the HandleUnauthorizedRequest method.
}
}
else
{
return false;//No need to create special unauthorized response.
}
}
}
You can use this attribute to decorate your controllers. You can even pass parameter in the constructor for more granular control on access management, like a required role to access de controller.

Scoping of callback functions which modify instance variables in Dart

While questions of this sort have been frequently asked, I think I have a more specific constraint that makes the problem a little more interesting. I am writing a client-side application in Dart using an MVC pattern. My goal is simple: listen for clicks on a button, trigger an async request to a back-end API, and present that data to the user.
Minimally, I have one each of a model, view, and controller class. The model class implements methods to make requests and bundle up the data it receives. The view class has the DOM subtree of interest as a field and implements methods to manipulate the elements therein. The controller has a single instance each of the model and view classes as its fields and registers event handlers on the elements of the view. The controller's event handlers fire off calls to the model to make requests and return data, which will then be passed to the view for rendering.
The issue arises when I attempt to capture the incoming data from the async request into an instance variable of the model. I'd like to keep everything nicely encapsulated (that's why I'm using Dart in the first place), and I'd like to avoid using a global variable to hold the data that comes from the async request. A minimal example of my current layout looks something like below. I've made all of the fields and methods public here for clarity's sake.
// view.dart
class FooView {
// The root element of the view with which we're concerned.
static final Element root = querySelector('#thisView');
FooView() { init(); }
void init() { root.hidden = false; }
// Appends the new data into an unordered list.
void update(List<Map<String,String>> list) {
UListElement container = root.querySelector('ul#dataContainer');
container
..hidden = true
..children.clear();
for ( Map<String,String> item in list ) {
container.append(new LIElement()
..id = item['id']
..text = item['text']
);
container.hidden = false;
}
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
List<Map<String,String>> dataList;
// Makes async request, returning data to caller.
List<Map<String,String>> getData() {
HttpRequest
.getString('example.com/api/endpoint')
.then( (String data) {
dataList = JSON.decode(data);
});
return dataList;
}
}
// controller.dart
class FooController {
FooModel model;
FooView view;
FooController() {
model = new FooModel;
view = new FooView;
}
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = view.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
view.update(model.getData());
});
}
}
The errors I'm seeing involve the model.dataList field coming up null at the end of all of this. My first blush is that I do not understand scoping of callback functions. The way I first understood it, the callback would handle the request's data when it arrived and just set the instance variable when it was ready. Perhaps the instance variable is aliased and modified within the scope of the callback, but the variable I want to return is never touched.
I have thought about passing a Future object to a method of the view, which will then just do the processing itself and add the elements to the DOM as a side effect. That technique would break my MVC design (even more than it's broken now in this minimal working example).
It is also very possible that I am using asynchronous programming completely incorrectly. Thinking more on this, my async call is useless because I basically make a blocking call to view.update() in the controller when the event fires. Maybe I should pass a request Future to the controller, and fire the request's then() method from there when the event handler is triggered.
In Dart, in what scope do callback functions reside, and how can I get data out of them with minimal side effects and maximal encapsulation?
N.B. I hate to belabor this oft-discussed question, but I have read previous answers to similar questions to no avail.
The getData method initiates the asynchronous HTTP request then immediately returns before having received/parsed the response. That is why model.datalist is null.
To make this work with minimal effort, you can make getData synchronous:
(note: I changed the dataList type, just to make it work with the sample JSON service http://ip.jsontest.com/)
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
Map<String, String> dataList;
// Makes async request, returning data to caller.
Map<String, String> getData() {
var request = new HttpRequest()
..open('GET', 'http://ip.jsontest.com/', async: false)
..send();
dataList = JSON.decode(request.responseText);
return dataList;
}
}
Though this may violate your objective, I agree with your concerns re: blocking call and would personally consider keeping the HTTP request asynchronous and making getData return a new future that references your model class or parsed data. Something like:
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
Map<String,String> dataList;
// Makes async request, returning data to caller.
Future<Map<String, String>> getData() {
return HttpRequest
.getString('http://ip.jsontest.com/')
.then( (String data) {
dataList = JSON.decode(data);
return dataList;
});
}
}
and in the controller:
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = FooView.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
model.getData().then((Map<String, String> dataList) {
view.update(dataList);
});
});
}
You return datalist in getData before the HttpRequest has returned.
// Makes async request, returning data to caller.
List<Map<String,String>> getData() {
return HttpRequest // <== modified
.getString('example.com/api/endpoint')
.then( (String data) {
return JSON.decode(data); // <== modified
});
// return dataList; // <== modified
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = view.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
model.getData().then((data) => view.update(data)); // <== modified
});
}
You can use Stream to make your design loosely coupled and asynchronous:
class ModelChange {...}
class ViewChange {...}
abstract class Bindable<EventType> {
Stream<EventType> get updateNotification;
Stream<EventType> controllerEvents;
}
class Model implements Bindable<ModelChange> {
Stream<ModelChange> controllerEvents;
Stream<ModelChange> get updateNotification => ...
}
class View implements Bindable<ViewChange> {
Stream<ViewChange> controllerEvents;
Stream<ViewChange> get updateNotification => ...
}
class Controller {
final StreamController<ViewChange> viewChange = new StreamController();
final StreamController<ModelChange> modelChange = new StreamController();
Controller.bind(Bindable model, Bindable view) {
view.controllerEvents = viewChange.stream;
model.controllerEvents = modelChange.stream;
view.updateNotification.forEach((ViewChange vs) {
modelChange.add(onViewChange(vs));
});
model.updateNotification.forEach((ModelChange mc) {
viewChange.add(onModelChange(mc));
});
}
ModelChange onViewChange(ViewChange vc) => ...
ViewChange onModelChange(ModelChange mc) => ...
}

httpmessagehandler - reading content

I created a message handler which will log the request and the response. ideally I want to
public class LoggingMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LogRequest(request);
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
LogResponse(response);
return response;
});
}
private void LogRequest(HttpRequestMessage request)
{
var writer = request.GetConfiguration().Services.GetTraceWriter();
var content = request.Content;
(content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
{
writer.Trace(request, "request", System.Web.Http.Tracing.TraceLevel.Info, t =>
{
t.Message = x.Result;
});
});
}
private void LogResponse(HttpResponseMessage response)
{
var request = response.RequestMessage;
var writer = request.GetConfiguration().Services.GetTraceWriter();
var content = response.Content;
(content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
{
writer.Trace(request, "response", System.Web.Http.Tracing.TraceLevel.Info, t =>
{
t.Status = response.StatusCode;
t.Message = x.Result;
});
});
}
}
and here is my client code.
public ActionResult Index()
{
var profile = Client.GetAsync("Vendor").Result.EnsureSuccessStatusCode().Content.ReadAsAsync<VendorProfileModel>().Result;
return View(profile);
}
Logging appears to be working. However, when this handler is registered my client code returns an empty object. If I remove this handler the model is successfully read from the response and displayed on screen.
Is there a way to read the content and display the results on the client?
after a few more days for digging around on the net I finally found the root problem and a solution. First the problem:
everything in webapi is async
my action uses Controller.User which in turn is calling Thread.CurrentPrinciple
I am using ITraceWriter as my logging abstraction
apparently there is a bug in the ITraceWriter mechanicism where the current profile is not propagated across threads. therefore, i loose the principle when i get to my controller action. therefore, my query returns an empty result, rather than a fully populated result.
solution: don't use ITraceWriter to log messages. It would have been nice to use the built in mechanics, but that doesn't work. here is the link to the same issue which provides more detail/context.
https://aspnetwebstack.codeplex.com/workitem/237

Resources