Razor:
#Html.TextBoxFor(kod => kod.Name)
#Html.ValidationMessage("Name","Client Error Message")
Controller:
[HttpPost]
public JsonResult JsonAddCustomer(Customers customer, string returnUrl)
{
if (customer.Name.Trim().Length == 0)
{
ModelState.AddModelError("Name", "Server Error Message");
}
//Eğer hata yoksa veri tabanına kayıt yapılıyor.
if (ModelState.IsValid)
{
try
{
CusOpp.InsertCustomer(customer);
return Json(new { success = true, redirect = returnUrl });
}
catch (Exception e)
{
ModelState.AddModelError("", "Error");
}
}
return Json(new { errors = GetErrorsFromModelState() });
}
I want to write validation error message. I did this like above, but #Html.ValidationMessage("Name","Client Error Message") does not work. In fact, I was already expecting it.
I want to show like this statement's result: #Html.ValidationMessageFor(m => m.name) ,but I cant use this, because I used entity-data-model.
Should I add [Required] statement to data-model classes or any way that I do this. Sorry for bad explanation.
Thanks.
You should return PartialViews instead of JSON in this case. Only in the case of success you could return JSON:
[HttpPost]
public ActionResult JsonAddCustomer(Customers customer, string returnUrl)
{
// Warning: the following line is something horrible =>
// please decorate your view model with data annotations or use
// FluentValidation.NET to validate it.
// Never write such code in a controller action.
if (customer.Name.Trim().Length == 0)
{
ModelState.AddModelError("Name", "Server Error Message");
}
//Eğer hata yoksa veri tabanına kayıt yapılıyor.
if (ModelState.IsValid)
{
try
{
CusOpp.InsertCustomer(customer);
return Json(new { success = true, redirect = returnUrl });
}
catch (Exception e)
{
ModelState.AddModelError("", "Error");
}
}
return PartialView(customer);
}
Now inside the success callback of your AJAX request you can test whether the POST action succeeded or not:
success: function(result) {
if (result.redirect) {
// we are in the success case => redirect
window.location.href = result.redirect;
} else {
// a partial view with the errors was returned => we must refresh the DOM
$('#some_container').html(result);
// TODO: if you are using unobtrusive client side validation here's
// the place to call the $.validator.unobtrusive.parse("form"); method in order
// to register the unobtrusive validators on the newly added contents
}
}
Here's a similar post that you might also read through.
Your Idea with the Required annotation on the model is a good approach. You can set a Error Message on the Required annotation.
[Required(ErrorMessage = "Please enter a name")]
and remove your if in your action..this:
if (customer.Name.Trim().Length == 0)
{
ModelState.AddModelError("Name", "Server Error Message");
}
the ModelState.IsValid will do the job for you on the client and server side.
And use your #Html.ValidationMessageFor(m => m.name) in your view
Related
in asp.net core I made a service to add new row and another one to update row. I call the service from the controller based on JS fetch request. now I need from the service response to return partialView and some Json like that
var data = { htmlContent : '<html table row >', mode : 'insert', isSuccessful : true }
// then when I get response from the controller
.then((data) => {
jsonObj.parse(date);
// ... some logic as follows
if (jsonObj.mode == 'create')
{
if (isSuccessful === 'true') {
// ... appendChild with [jsonObj.htmlContent]
} else {
// ... show modal with [jsonObj.htmlContent]
}
} else if (jsonObj.mode == 'update') {
if (isSuccessful === 'true') {
// ... insertInto (index) with [jsonObj.htmlContent]
} else {
// ... show modal with [jsonObj.htmlContent]
}
}
} else if (jsonObj.mode == 'delete') {
if (isSuccessful === 'true') {
// ... remove element with temp message [jsonObj.htmlContent]
} else {
// ... show modal with [jsonObj.htmlContent]
}
}
});
for the service I return response class like this
// service
public addNew()
{
try(){
_dbContext.add(...
var result = _dbContext.saveChanges();
// here is the question
// this is service not ActionResult
// I need to return here html content out of partialView
// along with some other Json data
return new response{htmlContent: partialView(''), mode: 'insert', isSuccessful: true};
}catch
{
return new response{htmlContent: '<h1>something went wrong !</h1>', mode: 'insert', isSuccessful: false};
}
}
public class Response
{
public Dynamic htmlContent { get; set; }
public bool isSuccessful { get; set; }
public Crud mode { get; set; }
}
public enum Crud () {
create, review, update, delete
}
in the controller I return to js the addNew result which is Response class
// after injection I use the service here
public IActionResult manage()
{
return _myService.addNew();
}
finally and again is possible to return partialView along with some Json data from the microservice like shown above
return new response{htmlContent: partialView(''), mode: 'insert', isSuccessful: true};
I think returning partialView is not allowed without IActionResult, however geeks absolutely know someway
A PartialView can only be interpreted and resolved to HTML by a razor view.
In your case, you are calling an API directly from Javascript so you have no razor component to interpret a PartialView response.
You either need to roll with the framework and use razor view or use javascript (or jQuery) to create the html that you want.
I have an Net Framework 4.5.2 project using MVC. I am using SignInManager.ExternalSignInAsync to checking windows domain users for an automatic login.
One user consistently returns Failure, and I'm trying to understand why. I've checked the ASPNetUsers, ASPNetLogins and ASPNetRoles tables and they are populated.
I use AuthenticationManager.GetExternalLoginInfoAsync() to retrieve the windows domain login, and that works fine for this user
Can anyone tell me why SignInManager.ExternalSignInAsync returns a failure on a login that just came from AuthenticationManager.GetExternalLoginInfoAsync()? Is there any way to ask SignInManager why it fails somebody? Pretty much at my wits end on this...any tips would be helpful!
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
try
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return View();
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
// this code attempts to create a user if it doesn't exist.
// it runs once for everybody except user in question
// problem user goes here every time, even though they have info in ASPNetUsers
if (loginInfo.Login.LoginProvider == "Windows")
{
bool resultMgr = await ManageWindowsLogins(loginInfo);
if (resultMgr) return RedirectToAction("Index", "Home");
else return RedirectToAction("NoLogin", "Account");
}
// Code should never go here
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
catch (Exception ex)
{
// code does not normally go here
...log error message code...
return View();
}
}
I have an application with both MVC and 'new' ApiController endpoints in ASP.NET Core 2.2 co-existing together.
Prior to adding the API endpoints, I have been using a global exception handler registered as middleware using app.UseExceptionHandler((x) => { ... } which would redirect to an error page.
Of course, that does not work for an API response and I would like to return an ObjectResult (negotiated) 500 result with a ProblemDetails formatted result.
The problem is, I'm not sure how to reliably determine in my 'UseExceptionHandler' lambda if I am dealing with an MVC or a API request. I could use some kind of request URL matching (eg. /api/... prefix) but I would like a more robust solution that won't come back to bite me in the future.
Rough psuedo-code version of what I'm trying to implement is:
app.UseExceptionHandler(x =>
{
x.Run(async context =>
{
// extract the exception that was thrown
var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
try
{
// generically handle the exception regardless of what our response needs to look like by logging it
// NOTE: ExceptionHandlerMiddleware itself will log the exception
// TODO: need to find a way to see if we have run with negotiation turned on (in which case we are API not MVC!! see below extensions for clues?)
// TODO: ... could just use "/api/" prefix but that seems rubbish
if (true)
{
// return a 500 with object (in RFC 7807 form) negotiated to the right content type (eg. json)
}
else
{
// otherwise, we handle the response as a 500 error page redirect
}
}
catch (Exception exofex)
{
// NOTE: absolutely terrible if we get into here
log.Fatal($"Unhandled exception in global error handler!", exofex);
log.Fatal($"Handling exception: ", ex);
}
});
});
}
Any ideas?
Cheers!
This might be a bit different than what you expect, but you could just check if the request is an AJAX request.
You can use this extension:
public static class HttpRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
if (request.Headers == null)
return false;
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
}
And then middleware with an invoke method that looks like:
public async Task Invoke(HttpContext context)
{
if (context.Request.IsAjaxRequest())
{
try
{
await _next(context);
}
catch (Exception ex)
{
//Handle the exception
await HandleExceptionAsync(context, ex);
}
}
else
{
await _next(context);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
//you can do more complex logic here, but a basic example would be:
var result = JsonConvert.SerializeObject(new { error = "An unexpected error occurred." });
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
return context.Response.WriteAsync(result);
}
see this SO answer for a more detailed version.
If you want to check whether the request is routed to ApiController, you could try IExceptionFilter to hanlde the exceptions.
public class CustomExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (IsApi(context))
{
HttpStatusCode status = HttpStatusCode.InternalServerError;
var message = context.Result;
//You can enable logging error
context.ExceptionHandled = true;
HttpResponse response = context.HttpContext.Response;
response.StatusCode = (int)status;
response.ContentType = "application/json";
context.Result = new ObjectResult(new { ErrorMsg = message });
}
else
{
}
}
private bool IsApi(ExceptionContext context)
{
var controllerActionDesc = context.ActionDescriptor as ControllerActionDescriptor;
var attribute = controllerActionDesc
.ControllerTypeInfo
.CustomAttributes
.FirstOrDefault(c => c.AttributeType == typeof(ApiControllerAttribute));
return attribute == null ? false : true;
}
}
Thanks to all of the advice from others, but I have realised after some more thought and ideas from here that my approach wasn't right in the first place - and that I should be handling most exceptions locally in the controller and responding from there.
I have basically kept my error handling middleware the same as if it was handling MVC unhandled exceptions. The client will get a 500 with a HTML response, but at that point there isn't much the client can do anyway so no harm.
Thanks for your help!
Hello I have been using Spring 3 for my project, I have been stuck in on point.
if(ajax){
User user = userTemplate.getUser(form.getCreator_id());
int isPremium = user.getPremium();
if ( isPremium == 1 ){
Map<String,String> resultMap = new HashMap<String,String>();
response.setHeader("Access-Control-Allow-Headers", "*");
response.addHeader("Access-Control-Allow-Origin", "*");
resultMap.put("result", "success");
return new Gson().toJson(resultMap);
}else{
return "redirect:/f/redirectedUrl?url="+form.getWeb_page();
}
}
redirectedUrl controller is just for redirecting, but if the request is ajax request then i want to response the request as json.
How can I achieve this, thanks.
Edit : I can understand if request is ajax or not. My problem is if it is ajax i want to response json, if it is not then i want to redirect.
Use this code in your controller to identify if request is ajax or not and based on that you can add your logic.
boolean ajax = "XMLHttpRequest".equals(
getRequest().getHeader("X-Requested-With"));
You can decide it from header("X-Requested-With") of your httpRequest object.
public ModelAndView getDetails(HttpServletRequest request, HttpServletRespone response) {
if(ajax) {
try {
new MappingJacksonHttpMessageConverter().write(object, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
} catch(Exception e) {
logger.error("Error when converting to json");
}
return null;
} else {
return new ModelAndView("viewName");
}
}
How do I handle exceptions thrown in a controller when jquery ajax calls an action?
For example, I would like a global javascript code that gets executed on any kind of server exception during an ajax call which displays the exception message if in debug mode or just a normal error message.
On the client side, I will call a function on the ajax error.
On the server side, Do I need to write a custom actionfilter?
If the server sends some status code different than 200, the error callback is executed:
$.ajax({
url: '/foo',
success: function(result) {
alert('yeap');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
and to register a global error handler you could use the $.ajaxSetup() method:
$.ajaxSetup({
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
Another way is to use JSON. So you could write a custom action filter on the server which catches exception and transforms them into JSON response:
public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
and then decorate your controller action with this attribute:
[MyErrorHandler]
public ActionResult Foo(string id)
{
if (string.IsNullOrEmpty(id))
{
throw new Exception("oh no");
}
return Json(new { success = true });
}
and finally invoke it:
$.getJSON('/home/foo', { id: null }, function (result) {
if (!result.success) {
alert(result.error);
} else {
// handle the success
}
});
After googling I write a simple Exception handing based on MVC Action Filter:
public class HandleExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
filterContext.Exception.Message,
filterContext.Exception.StackTrace
}
};
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}
}
and write in global.ascx:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleExceptionAttribute());
}
and then write this script on the layout or Master page:
<script type="text/javascript">
$(document).ajaxError(function (e, jqxhr, settings, exception) {
e.stopPropagation();
if (jqxhr != null)
alert(jqxhr.responseText);
});
</script>
Finally you should turn on custom error.
and then enjoy it :)
Unfortunately, neither of answers are good for me. Surprisingly the solution is much simpler. Return from controller:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);
And handle it as standard HTTP error on client as you like.
I did a quick solution because I was short of time and it worked ok. Although I think the better option is use an Exception Filter, maybe my solution can help in the case that a simple solution is needed.
I did the following. In the controller method I returned a JsonResult with a property "Success" inside the Data:
[HttpPut]
public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave)
{
if (!ModelState.IsValid)
{
return new JsonResult
{
Data = new { ErrorMessage = "Model is not valid", Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
try
{
MyDbContext db = new MyDbContext();
db.Entry(employeToSave).State = EntityState.Modified;
db.SaveChanges();
DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];
if (employeToSave.Id == user.Id)
{
user.Company = employeToSave.Company;
user.Language = employeToSave.Language;
user.Money = employeToSave.Money;
user.CostCenter = employeToSave.CostCenter;
Session["EmployeLoggin"] = user;
}
}
catch (Exception ex)
{
return new JsonResult
{
Data = new { ErrorMessage = ex.Message, Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
return new JsonResult() { Data = new { Success = true }, };
}
Later in the ajax call I just asked for this property to know if I had an exception:
$.ajax({
url: 'UpdateEmployeeConfig',
type: 'PUT',
data: JSON.stringify(EmployeConfig),
contentType: "application/json;charset=utf-8",
success: function (data) {
if (data.Success) {
//This is for the example. Please do something prettier for the user, :)
alert('All was really ok');
}
else {
alert('Oups.. we had errors: ' + data.ErrorMessage);
}
},
error: function (request, status, error) {
alert('oh, errors here. The call to the server is not working.')
}
});
Hope this helps. Happy code! :P
In agreement with aleho's response here's a complete example. It works like a charm and is super simple.
Controller code
[HttpGet]
public async Task<ActionResult> ChildItems()
{
var client = TranslationDataHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("childItems);
if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
return Json(content, JsonRequestBehavior.AllowGet);
}
else
{
return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
}
}
}
Javascript code in the view
var url = '#Html.Raw(#Url.Action("ChildItems", "WorkflowItemModal")';
$.ajax({
type: "GET",
dataType: "json",
url: url,
contentType: "application/json; charset=utf-8",
success: function (data) {
// Do something with the returned data
},
error: function (xhr, status, error) {
// Handle the error.
}
});
Hope this helps someone else!
For handling errors from ajax calls on the client side, you assign a function to the error option of the ajax call.
To set a default globally, you can use the function described here:
http://api.jquery.com/jQuery.ajaxSetup.