public async Task<JsonResult> Save(List<SalesNewItemModel> aSalesNewItemModel)
{
string msg = await _aSalesNewItemManager.Save(aSalesNewItemModel);
return Json(msg, JsonRequestBehavior.AllowGet);
}
Shows Error type string is not awaitable
Since the method doesn't call anything async, just make it non-async.
public JsonResult Save(List<SalesNewItemModel> aSalesNewItemModel)
{
string msg = _aSalesNewItemManager.Save(aSalesNewItemModel);
return Json(msg, JsonRequestBehavior.AllowGet);
}
Or you should change _aSalesNewItemManager.Save to return Task<string> and make use of asynchronous processing in that method. For example async IO.
Related
//create post action method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(ProductType productType)
{
if (ModelState.IsValid)
{
_db.ProductTypes.Add(productType);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(productType);
}
In this case it's doesn't show any error but it does not work.. Where is the mistake?
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Can you please check the > Views > _ViewImports.cshtml
If the above #addTagHelper doesn't exist please add this...
public IActionResult Create()
{
return View();
}
//create post action method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("column1,column2,column3,..")] ProductType productType)
{
if (ModelState.IsValid)
{
_db.Add(productType);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(productType);
}
You need to remove ProductTypes. before .Add(productType); function.
The correct statement is -
_db.Add(productType);
Also, You can bind the column
Would you try this code again. Hope it will work. If doesn't work, can you share the view code pls. I would like to solve your problem.
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);
}
}
}
I have been trying to sort out this for hours and could not find a solution.
I am using a Web Api MVC project and trying to convert an IEnumerable list to a paged list async. I'm able to compile but I'm still getting a runtime error on the ToPagedListAsync() line.
The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068."
1st Layer:
public async Task<IEnumerable<MatchingCriteria>> GetMatchingCriterias(int id)
{
return await _ctx.MatchingCriterias.Include(mc => mc.RuleDefinition).Where(mc => mc.RuleDefinitionId == id).ToListAsync();
}
2nd Layer:
internal async Task<IEnumerable<MatchingCriteria>> GetMatchingCriterias(int id)
{
using (CrawlerDbContext db = new CrawlerDbContext())
{
var matchCriteriaMgr = new MatchingCriteriaManager(db);
return await matchCriteriaMgr.GetMatchingCriterias(id);
}
}
Controller:
public async Task<ActionResult> Index(int? id, string sortOrder, string currentFilter, string searchString, int? page){
var matchingCriterias = await _crawlerProvider.GetMatchingCriterias(id.Value);
//...
IQueryable<MatchingCriteria> matchCrit = matchingCriterias.AsQueryable();
//Error here -> return View(await matchCrit.ToPagedListAsync(pageNumber, pageSize));
}
if I do instead in the controller:
var matchingCriterias = _db.MatchingCriterias.Include(mc => mc.RuleDefinition);
then:
return View(await matchingCriterias.ToPagedListAsync(pageNumber, pageSize)
That works well!
I could return a DbSet on the nested methods but I could not use the ToListAsync() in the 1st layer;
Is there a way to make the list IQueryable?Any other ideas or suggestions?
Well, I fixed it myself by creating an AsyncQueryable extension as mentioned here
Then I could call the pagedListAsync() method like bellow:
return View(await matchingCriterias.AsAsyncQueryable().ToPagedListAsync(pageNumber, pageSize)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
CORS with WebAPI for XmlHttpRequest
I'm trying to implement cross-domain ajax post to my webApi project. I had few troubles with that:
1. I always was getting 204 error until changed my webapi action from
public void submit(Submission model)
to
public bool submit(Submission model)
don't know why, but now I'm getting 200 OK status
2. Still my ajax firing error callback.
3. Long time ago I solved this kind of error of cross-domain posting by adding
HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
to my controller. But now in webApi i'm inherent from : ApiController and this trick doesn't work. Shows me compiler Error an object reference is required for the non-static field, method, or property"System.Web.HttpContext.Response.get"
I have tryed to post via dataType: 'JSONP' but I get null model.
Here goes Javascript request:
var model = {
"type": $("#model-type").val(),
"subject": $("#subject-text").val(),
"body": $("#body-text").val()
};
$.ajax({
type: "POST",
dataType: 'JSONP',
url: $("#submit-url").val(),
data: model,
success: function () {
alert("Succesfully submitted");
},
error: function () {
alert("Error...");
}
});
What I'm doing wrong?
SOLVED
Thanks to everybody for helping me out. I found solution in one of the comment links. I used following approach, which I find pretty simple.
Source:
Implementing CORS support in ASP.NET Web APIs
What I made:
1. Created new Class in my project: CorsHandler.cs and just copy-pasted following code:
public class CorsHandler : DelegatingHandler
{
const string Origin = "Origin";
const string AccessControlRequestMethod = "Access-Control-Request-Method";
const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
bool isCorsRequest = request.Headers.Contains(Origin);
bool isPreflightRequest = request.Method == HttpMethod.Options;
if (isCorsRequest)
{
if (isPreflightRequest)
{
return Task.Factory.StartNew(() =>
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
if (accessControlRequestMethod != null)
{
response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
}
string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
if (!string.IsNullOrEmpty(requestedHeaders))
{
response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
}
return response;
}, cancellationToken);
}
else
{
return base.SendAsync(request, cancellationToken).ContinueWith(t =>
{
HttpResponseMessage resp = t.Result;
resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
return resp;
});
}
}
else
{
return base.SendAsync(request, cancellationToken);
}
}
}
Opened my Global.asax and modifyed Application_Start :
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configuration.MessageHandlers.Add(new CorsHandler());
}
Pay attention to the last line in action.
This approach is compatible with MVC3 and .NET 4.0. Works great, now I can handle "success" and "error" callbacks in ajax.
Answers to your questions respectively:
Status 204 is not an error, which means no content to return but everything's good. Here's the definition of 204 in RFC2616
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an
entity-body, and might want to return updated metainformation. The
response MAY include new or updated metainformation in the form of
entity-headers, which if present SHOULD be associated with the
requested variant.
If the client is a user agent, it SHOULD NOT change its document view
from that which caused the request to be sent. This response is
primarily intended to allow input for actions to take place without
causing a change to the user agent's active document view, although
any new or updated metainformation SHOULD be applied to the document
currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always
terminated by the first empty line after the header fields.
Could you articulate what's the error you met? The ASP.NET Web API currently doesn't have a JSONP formatter out of box. Here's some 3rd part implementation:
http://www.west-wind.com/weblog/posts/2012/Apr/02/Creating-a-JSONP-Formatter-for-ASPNET-Web-API
http://www.nuget.org/packages/WebApi.JsonP
I hope they're helpful.
In Web API the way in which you refers to an Response is not through HttpContext. There are multiple ways to access.
The first option is to define action return HttpResponse directly.
public HttpResponseMessage Get(int id)
{
var response = this.Request.CreateResponse();
response.StatusCode = HttpStatusCode.OK;
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
The second option is to use ActionFilter:
// define action filter for cross domain
public class CrossDomainActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
bool needCrossDomain = true;
if (needCrossDomain)
{
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
base.OnActionExecuted(actionExecutedContext);
}
}
// At Controller
// GET api/values/5
[CrossDomainActionFilter]
public string Get(int id)
{
return "value";
}
The last option is to use MessageHandler:
public class CrossDomainMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
}
If you want to send information to another domain from ajax then you need to use jsonp (note this only works with get requests not post requests). Another alternative (if you are in control of both domains) is to use ARR (application request routing) to trick the browser into thinking the request is local then using ARR to rewrite the request to another domain. Using this technique you can use simple ajax gets and posts like normal.
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