MVC return json info when file not found - asp.net-mvc

i have application where user can download excel report using this button:
my method looks following:
[HttpPost]
public ActionResult GetYearlyReport(int plantId)
{
string fileName = Reports.GenerateYearlyReport();
if (!String.IsNullOrEmpty(fileName))
{
byte[] fileBytes = GetFile(fileName);
return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
}
return Json(new { Result = "ERROR", Message = "Missing some parameters." });
}
Now , wheren filename isn't empty then i got the file, but when it is then i am redirected to non existed page GetYearlyReport, while I would like to just say message from json, is that possbile?

Why not just add another if() statement to handle the scenarios where file names are empty, and return an error and handle it client side?
$.ajax({
url: 'xxx/GetYearlyReport',
data: { plantId: plantId},
type: 'POST',
error: function (xhr, textStatus, exceptionThrown) {
if (xhr.status == xxx) {
alert(xhr.responseText);
}
},
success: function (data) {
if(data.Result = 'ERROR'){
//do something
alert(data.Message);
}
}
});
Or better define a common error handler for your ajax calls?
$(document).ajaxError(function (e, xhr, settings) {
if (xhr.status == 401)
{
alert("unauthorized");
}
else if (xhr.status == 0) {
alert(' Check Your Network.');
} else if (xhr.status == 404) {
alert('The resource you are looking for can not be found.');
} else if (xhr.status == 500) {
alert('Internel Server Error.');
} else {
alert('Unknow Error.\n' + x.responseText);
}
});

Your code seems fine, I believe redirection is occurred in the Reports.GenerateYearlyReport method, there must be a way to check the result of the method before invoke it.

Related

Passing String parameter Value Through angular Service parameter Value is Automatically Appends Some Special Character

Here's my Angular controller
//Save And Update
$scope.AddUpdateBusinessType = function() {
var businessType = {
Code: $scope.businessCode,
BusiType: $scope.businessType
};
var getBusinessTypeAction = $scope.BusinessTypeAction;
if (getBusinessTypeAction == "Update") {
businessType.BusinessTypeId = $scope.businessTypeId;
var getBusinessTypeData = businessTypeService.updateBusinessType(businessType);
getBusinessTypeData.then(function (msg) {
GetAllBusinessType();
$scope.ClearBusinessTypeForm();
alert("Record Updated Successful");
$scope.BusinessTypeAction = "";
$scope.divBusinessType = false;
}, function () {
alert('Error in Updating Record');
});
} else {
**// Save Section**
var getExistBusinessCode = businessTypeService.checkBusinessTypeCode(businessType.Code);
getExistBusinessCode.then(function (businessTypeCode) {
debugger;
if (businessTypeCode == true) {
alert('Business Type Code Already Exist');
} else {
debugger;
var getBusinessTypeData = businessTypeService.addBusinessType(businessType);
getBusinessTypeData.then(function (msg) {
GetAllBusinessType();
$scope.ClearBusinessTypeForm();
alert("Record Added Successful");
$scope.divBusinessType = false;
}, function () {
alert("Error Occured In Saving Data");
});
}
},function() {
alert('Error Occured While Checking Records');
});
}
}
In the above code Save Section I am trying to check if a value is exists in a database so I'm passing a string value to: checkBusinessTypeCode(businessType.Code) Service.When I Debug and See Value its Seems Normal.
Here's My Service:
//Check Business Code
this.checkBusinessTypeCode = function (businessTypeCode) {
debugger;
var response = $http({
method: "post",
url: "/BusinessType/CheckBusinessTypeDetailByCode",
params: {
businessTypeCode: JSON.stringify(businessTypeCode)
}
});
return response;
}
But when Passing To Controller string value I get some unexpected behavior.
two \\ always appear automatically
example
"\"stringvalue\""
I'm Still Having Above Problem
but as a quick solution i did code as follows
public bool _CheckBusinessTypeDetailByCode(string businessTypeCode)
{
string bisCode = businessTypeCode.Replace("\"", "");
bool isExist;
isExist = _IBusinessTypeRepository.IsExist(x => x.IsActive && !x.IsDelete && x.Code == bisCode);
return isExist;
}
I don't know is it bad practice or not , any way it is solved my problem.
Before did this modification
string businessTypeCode always gives value as
"\"somevalue\""

ASP.Net MVC, WebAPI, AngularJS - Check if value exists in database

I am using webapi and angularjs in my ASP.net MVC app. Everything is working good but in my insert (post) method I need to check if a value exists in the db before doing an insert. I am not sure where that should go. I ruled out the webapi because a void does not return a value. The logical place seems to be the controller, but I cannot find the right way to call my angular getEmployee(id) method from within the insert controller method. Any help is appreciated.
Angular controller (post):
$scope.insertEmployee = function (employee) {
employeeFactory.insertEmployee(employee)
.success(function (emp) {
$scope.employee = emp;
})
.error(function (error) {
$scope.status = 'Unable to load employee data: ' + error.message;
});
};
Angular factory (post):
factory.insertEmployee = function (employee) {
url = baseAddress + "employee/insert/";
$http.post(url, employee).success(function (data) {
alert("Saved Successfully!!");
}).error(function (data) {
$scope.error = "An Error has occured while saving employee! " + data;
});
};
webapi controller post method:
[Route("api/employee/insert/")]
public void Post(Employee employee)
{
if (ModelState.IsValid)
{
context.Employee.Add(employee);
context.SaveChanges();
}
}
Angular controller (get):
$scope.getEmployees = function (term) {
employeeFactory.getEmployees(term)
.success(function (data) {
$scope.employees = data;
})
.error(function (error) {
$scope.status = 'Unable to load employee data: ' + error.message;
});
};
I would suggest doing this in your web-api server side. You can construct an exception and throw it. Some pseudo-code:
[Route("api/employee/insert/")]
public void Post(Employee employee)
{
if (ModelState.IsValid)
{
// verify doesn't already exist
if(...item-already-exists...) {
var resp = new HttpResponseMessage(HttpStatusCode.Conflict)
{
Content = new StringContent("Employee already exists!")),
ReasonPhrase = "Employee already exists!"
}
throw new HttpResponseException(resp);
}
context.Employee.Add(employee);
context.SaveChanges();
}
}
Your factory doesn't match your controller. If you want to use success and error from employeeFactory.insertEmployee, it needs to return the promise:
factory.insertEmployee = function (employee) {
url = baseAddress + "employee/insert/";
return $http.post(url, employee);
};
So then you can do
employeeFactory.insertEmployee(employee).success( ... )
Now to answer your question you could either do a database read in insertEmployee to check if the value exists before you insert it. Or save a server call and do the check during the insert request: if the employee exists, return an error or a specific message to tell the client.
With the help of floribon and Nicholas Smith I managed to come up with a solution that bubbles the error up to my view, which I display in a div element. This is only bare bones, but is a start.
My angular controller:
$scope.insertEmployee = function (employee) {
employeeFactory.insertEmployee(employee)
.success(function (data) {
$scope.employee = data;
$scope.status = 'The item was saved';
})
.error(function (error) {
$scope.status = 'Unable to save the employee data: ' + error;
});
};
My angular factory:
factory.insertEmployee = function (employee) {
url = baseAddress + "employee/insert/";
return $http.post(url, employee);
};
my webapi controller:
[Route("api/employee/insert/")]
public HttpResponseMessage Post(Employee employee)
{
HttpResponseMessage response;
// check for the employee
var employeeCheck = context.Employee
.Where(b => b.EmployeeNumber == employee.EmployeeNumber)
.FirstOrDefault();
if (employeeCheck == null)
{
// save the item here
response = Request.CreateResponse(HttpStatusCode.OK);
}
else
{
response = Request.CreateResponse(HttpStatusCode.Conflict, "The item already exists");
}
return response;
}
The result is the message is "Unable to save the employee data: The item already exists".

How to redirect an Ajax Method session on timeout

So I got a ajax method that returns a JSON result, but part of the method is to check if the session is valid.
So If a user refreshed a page, the ajax method is called, in which it throws an exception as the session has expired, now the method wants to return a JSON result, but instead I want to redirect them to the login page.
how do I do this?
public JsonResult GetClients()
{
var usertoken = new UserToken(this.User.Identity.Name);
if (usertoken.AccountId != null)
{
return new JsonResult() {Data = model, JsonRequestBehavior = JsonRequestBehavior.AllowGet};
}
else
{
//Redirect Here
}
AFAIK you would only be able to do this via JavaScript since your call is using ajax, the solution to the other post would not work since the redirect header would not be honored for an ajax request.
You might want to add a status or hasExpire property to your return result:
[HttpPost]
public ActionResult GetClients()
{
var usertoken = new UserToken(this.User.Identity.Name);
if (usertoken.AccountId != null)
{
return Json(new { data = model, status = true });
}
else
{
return Json(new { data = null, status = false });
}
On your ajax call:
$.ajax('/controller/getclients', { }, function(data) {
if(data.status == true) {
// same as before you've got your model in data.data...
} else {
document.location.href = '/account/login';
}
});
Hope that help.
In Controller code, check for session validity. For example
if (Session["UserName"] == null)
{
return Json(new
{
redirectUrl = ConfigurationManager.AppSettings["logOffUrl"].ToString(),
isTimeout = true
});
}
In .js file check like the following
success: function (data) {
if (data != '' && typeof data != 'undefined') {
if (data.isTimeout) {
window.location.href = data.redirectUrl;
return;
}

MVC: pass parameter to action using Jquery.ajax()

I'm pretty new to MVC. I need to make ajax call to an Action with parameters using html.Action(). I'm unable to pass this..
Hope it will be helpful for other MVC begineers as well..
HTML:
<%: Html.ActionLink("Add Race", "AddRace",
new {eventId = Model.EventId, fleetId=Model.SelectedFleet.ID},
new{#onclick=string.Format("return checkFleetAddedandScroing()")}) %>
Jquery:
function checkFleetAddedandScroing() {
debugger;
$.ajax({
type: "GET",
url: '<%=Url.Action("CheckFleetExists")%>',
dataType: "json",
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}
Action:
public JsonResult CheckFleetExists(Guid fleetId )
{
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetId);
}
catch
{
}
return Json(exists, JsonRequestBehavior.AllowGet);
}
I need to pass fleetid to action which is in Model.SelectedFleet.ID. Its being used somewhere on pages. But i'm unable to use that somehow..
please suggest where i'm doing wrong...
It looks like you are trying to invoke a controller action using AJAX when the link is clicked and depending on the result of this call either allow the user to be redirected to the actual AddRace action or be prompted with an error message.
The problem with your code is that you are attempting to return true/false from within the success AJAX callback which doesn't make any sense. You need to always return false from the click callback and inside the success callback, depending on the returned value from the server, redirect manually using the window.location.href function.
HTML:
<%: Html.ActionLink(
"Add Race",
"AddRace",
new {
eventId = Model.EventId,
fleetId = Model.SelectedFleet.ID
},
new {
data_fleetid = Model.SelectedFleet.ID,
#class = "addRace"
}
) %>
Jquery:
<script type="text/javascript">
$(function () {
$('.addRace').click(function (evt) {
$.ajax({
type: 'GET',
url: '<%= Url.Action("CheckFleetExists") %>',
cache: false,
data: { fleetId: $(this).data('fleetid') },
success: function (data) {
if (data.exists) {
// the controller action returned true => we can redirect
// to the original url:
window.location.href = url;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
}
},
error: function (req) {
}
});
// we make sure to cancel the default action of the link
// because we will be sending an AJAX call
return false;
});
});
</script>
Action:
public ActionResult CheckFleetExists(Guid fleetId)
{
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetId);
}
catch
{
}
return Json(new { exists = exists }, JsonRequestBehavior.AllowGet);
}
Remark: inside your AddRace controller action don't forget to perform the same verification as you are doing inside your CheckFleetExists. The user could simply disable javascript and the AJAX call will never be done.
change your action like this :
public JsonResult CheckFleetExists(string fleetId)
{
var fleetGuid = Guid.Parse(fleetId);
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetGuid );
}
catch
{
}
return new JsonResult{ Data = exists};
}
and change you ActionLink so :
<%: Html.ActionLink("Add Race", "AddRace",
new {eventId = Model.EventId, fleetId=Model.SelectedFleet.ID},
new{onclick=string.Format("return checkFleetAddedandScroing({0})",Model.SelectedFleet.ID)}) %>
and your script block may look something like this :
function checkFleetAddedandScroing($fleetId) {
$.ajax({
type: "POST",
url: '<%=Url.Action("CheckFleetExists")%>',
dataType: "json",
data : { "fleetId" : $fleetId },
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}
Problem was in answers that url to action was not complete..i did it using this way
function checkFleetAddedandScroing() {
// debugger;
$.ajax({
type: "POST",
url: '<%=Url.Action("CheckFleetExists", new {eventId=Model.EventId})%>',
dataType: "json",
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}

ASP.NET MVC Ajax Error handling

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.

Resources