I am using Castle Windsor as DI and using reposity to access and implement the data layers.
As I have implemented all the data access layer in my repo, it is time to call those methods in my API controller. SO I have 'getAllReportsByClient method' and 'CreateReport' POST method. So, in order to test if some methods are working without actually implementing the view and AJAX call, how can I insert sample data using my 'Create Report' method?
The method from repo is below:
public void CreateReport(TReportHeaderModel model)
{
using (var connection = new TReportEntitiesConnection())
{
connection.THeader.Add(new THeader()
{
ClientID=model.ClientID,
ID=model.ID,
THeaderTitle=model.THeaderTitle,
RowNumber=model.RowNumber
});
foreach (var d in model.TReports)
{
connection.TReport.Add(new TReport()
{
ID=d.ID,
TReportName=d.TReportName,
URL=d.URL,
RowNumber=d.RowNumber,
});
}
connection.SaveChanges();
}
throw new NotImplementedException();
}
The below is HTTPPOST createReport call in Controller:
[HttpPost]
public ActionResultModel CreateReport([FromBody] TReportHeaderModel model)
{
try
{
_tReportingService.CreateReport(model);
return new ActionResultModel() //return void, must not be followed by object expression
{
Success = true,
Message = "Report Successfully Created."
};
}
catch (Exception ex)
{
return new ActionResultModel()
{
Success = false,
Message = "Report not created.",
Obj=ex.Message
};
}
}
You could use Postman(https://www.getpostman.com/) or Fiddler(www.telerik.com/fiddler) to emulate the request. Even better, you could write a test using a testing framework.
Related
I have an Syncfusion Asp.net grid performing CRUD operations.
public ActionResult Insert(CRUDModel<Source> newItem)
{
using (var context = new ImageStormEntities())
{
context.Sources.Add(newItem.Value);
context.SaveChanges();
}
return Json(newItem.Value);
}
cshtml:
#Html.EJS().Grid("DataGrid").DataSource(ds => ds.Json(ViewBag.datasource).UpdateUrl("/Management/Update").InsertUrl("/Management/Insert").RemoveUrl("/Management/Remove").Adaptor("RemoteSaveAdaptor")).Columns(col =>
{
col.Field("id").IsPrimaryKey(true).Visible(false).Add();
col.Field("ResourceGroup").HeaderText("Source VM Resource Group").Add();
col.Field("VMName").HeaderText("Source VM Name").Add();
col.Field("imageVersion").HeaderText("Image Version").Add();
}).ActionFailure("OnActionFailure").AllowTextWrap(true).TextWrapSettings(text => { text.WrapMode(Syncfusion.EJ2.Grids.WrapMode.Header); }).AllowPaging().FilterSettings(filter => { filter.Type(Syncfusion.EJ2.Grids.FilterType.Menu); }).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).ShowDeleteConfirmDialog(true).Mode(Syncfusion.EJ2.Grids.EditMode.Dialog); }).Toolbar(new List<string>
() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render()
On the page, I have:
<script>
function OnActionFailure(args) {
alert(args.error.status + " : " + args.error.statusText);
}
</script>
That returns a simple toast message when values break the db constraints, but values are empty.
I want to send usefull info to user.
I can catch the error, what do I return to make this work.
Also, I would rather the use got a Messagebox to discharge rather that a toast.
Changed your controllers code this will fix your issue
To
public ActionResult Insert(CRUDModel<Source> newItem)
{
using (var context = new ImageStormEntities())
{
if(newItem.Value! = null)
{
context.Sources.Add(newItem.Value);
context.SaveChanges();
}
else
{
throw new Exception("Empty values cannot be inserted");//Add custom
exception message
}
}
return Json(newItem.Value);
}
and in your js add lime this
<script>
function OnActionFailure(args) {
var errorMessage = args[0].error.responseText.split("Exception:")[1].split('<br>')[0]; //extract the message from args
alert(errorMessage);
//you will get exact error that you have returned from serverside in errorMessage
}
</script>
I am working on a MVC Web App which is calling a Web API. In my Create (POST) method, a user will enter email addresses of some users in the database. I have a check to enter the email only if the email does not already exist in the database or not. If it already exists, I want to be able to show an error message to the user "Email already exists".
I thought HttpStatusCode.NotFound, "Email exists already." would work, but I think it will only show in PostMan. How can I show it on the MVC side with like ViewBag.ErrorMessage?
API
public IHttpActionResult PostApprovedUsers(ApprovedUsers approvedUsers)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (!db.ApprovedUsers.Any(u => u.Email == approvedUsers.Email))
{
db.ApprovedUsers.Add(approvedUsers);
db.SaveChanges();
}
else
{
return Content(HttpStatusCode.NotFound, "Email exists already.");
}
return CreatedAtRoute("DefaultApi", new { id = approvedUsers.Email }, approvedUsers);
MVC Create
public ActionResult Create([Bind(Include = "Email,FirstName,LastName")] ApprovedUsers approvedUsers)
{
using (WebClient client = new WebClient())
{
token = Session.GetDataFromSession<string>("access_token");
client.Headers.Add("authorization", "Bearer " + token);
client.UploadValues(apiUrl, "POST", new NameValueCollection()
{
{ "Email", approvedUsers.Email },
{ "FirstName",approvedUsers.FirstName },
{ "LastName",approvedUsers.LastName }
});
}
return RedirectToAction("Index");
}
The main problem with what you were seeing is that you were not in fact doing anything with the return value of webclient. That is ok though, since based on our discussion everything is in the same project and that would not be how you would want to do this using ASP.NET MVC and Web API.
Since these are all in the same project, we do want to combine common functionality but not within a controller. The DB service should be abstracted away into a seperate project - or class - and then injected into both controllers using some form of IoC Container. There are a couple of options available and I personally usually use Ninject for my .NET projects.
Assuming you have that functionality your MVC Controller and API controller should then both program against that abstraction. Interface based programming is how .NET works best.
With that in mind your new API controller would look something like this:
public IHttpActionResult PostApprovedUsers([Bind(Include="Email, FirstName, LastName")]ApprovedUser approvedUser)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (_db.UserExists(approvedUser))
{
return Content(HttpStatusCode.NotFound, "Email exists Already");
}
_db.AddUser(approvedUser);
return CreatedAtRoute("DefaultApi", new {id = approvedUser.Email}, approvedUser);
}
Where _db is the service that gets injected into the controller. Please not how common functionality such as checking to see if a user exists and adding a user are wrapped behind the abstraction:
public interface IMyFakeDbService
{
IQueryable<ApprovedUser> ApprovedUsers { get; }
int RemoveUser(ApprovedUser user);
int RemoveUser(string email);
bool UserExists(ApprovedUser user);
void AddUser(ApprovedUser user);
}
This then brings us to your MVC Controller. The same principle applies; since all the common functionality is in the db service just inject that into the controller instead of calling the API controller. You will see that you can use ModelState.AddModelError here to pass information back into the view.
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create([Bind(Include = "Email, FirstName, LastName")]ApprovedUser user)
{
if (ModelState.IsValid)
{
if (!_db.UserExists(user))
{
_db.AddUser(user);
return RedirectToAction("Index");
}
ModelState.AddModelError("","A user with that email already exists");
}
return View();
}
Finally
I made a public git repo with a complete project here
The DB calls should be async. You are wasting server resources if not
If you want to learn MVC real quick I would suggest Pro ASP.NET MVC 5 and Pro ASP.NET Web API2
I always use Ok<T>, where T is a model I defined which have 3 variables, one will identify the status (true, false) and one will be a string message, and one will have data type of List<object> which I need to receive at end point, then you can modify the error message as you want
in your case instead of this
return BadRequest(ModelState);
I will replace it with something like this
return Ok<MyResponse>(new MyResponse{ Message = "Error Message Here", Status = false});
then once you get your content you can desirialize it into your object
MyResponse response = new MyResponse();
HttpResponseMessage response = await client.GetAsync(path);
// ok will return success status code, but you will depend on your status to know if it was success or error happened
if (response.IsSuccessStatusCode)
{
// Desirialize your result
response = await response.Content.ReadAsAsync<MyResponse>();
}
// then get the message,
if(response.Status)
{
//it was fine, return something ..
}
else {
// Error happened, get your error message and disaply it, if you want as viewbag
ViewBag.ErrorMessage = response.Message;
// do something
}
I have a solution with two project , one is my webapi service and another is my mvc for project . I am calling the service from my controller. My service has GET,POST,PUT all methods. In my view i am using a submit button and which calles the post controller method which in turn call my service . Here the issue i am facing is it is calling always the GET method. I want to fire the POST method in my service
controller post method
[HttpPost]
public ActionResult Create(Test test)
{
if (ModelState.IsValid)
{
Test objTest = MyService.Create(test);
if (objTest == null)
{
return HttpNotFound();
}
return RedirectToAction("Index");
}
}
Here calls the service
**public Test Create(Test test)
{
string uri = baseUri + "Test/";
using (HttpClient httpClient = new HttpClient())
{
Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, new StringContent(JsonConvert.SerializeObject(Test)));
return JsonConvert.DeserializeObjectAsync<Test>(response.Result.Content.ReadAsStringAsync().Result).Result;
}
}**
This is the post
**// POST api/Test
public HttpResponseMessage PostTest(test test
{
if (ModelState.IsValid)
{
db.Test.Add(test);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, test);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = test.TestID }));
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
****************
**// GET api/Test
public IEnumerable<Test> GetTest()
{
var tests= db.Tests;
return tests.AsEnumerable();
}**
It always calls the above Get method . I am completely new to web api service. Can some one guide me with proper way , where i am wrong. I am not using any ajax to call post method.
Well, look at the method you're using:
httpClient.GetStringAsync(uri);
Get does exactly what the name implies. It makes a GET request to the resource. If you want to use a different HTTP verb, use one of the other methods available.
For example:
httpClient.PostAsync(uri, someContentObject);
Or, using HttpClientExtensions:
httpClient.PostAsJsonAsync(uri, test);
This is how you do a POST with some data.It's similar to the GET request but in this case since you want to send a POST this will be aplicable. Also notice its simple to add POST data (when compared with HttpWebRequest)
httpClient.PostAsync(uri, new StringContent(data));
I am trying to delete item from table. There is Ajax link for it.
#Ajax.ActionLink("Delete", "DeleteConfirm", new { id = Model.ID }, new AjaxOptions {
HttpMethod = "POST", UpdateTargetId = "TableID", OnSuccess = "CloseDialog", OnFailure = "AlerDialog"
})
It calls DeleteConfirm method from controller with POST method. I made simple controller which should do something so ActionLink should catch error and run OnFailure function (to show alert dialog).
Controller:
public ActionResult DeleteConfirm(int id)
{
// code here
}
What to return from controller method so OnFailure function invokes?
OnError is fired when error happens on serverside. By error, I mean exception, and I think you can't pass exception message on clientside except of 500 Server error.
I think that good aproach is to have some CustomResponse class that your action will return.
In your case, something like:
Class DeletionResponse
{
public bool IsDeletionSuccesfull {get; set; }
public string Message {get; set;}
}
In DeleteConfirm action you create new response, which maybe needs to inheriteActionResult class(I'm not sure because I'm new to MVC). If some error ocures while deleting, set DeletionSuccesfull to false, and Message to message of exception, or some custom message.
On client side, the point is to examine success in OnSuccess handler, and then decide what to do.
Something like:
function handleResponse(deletionResponse){
if(deletionResponse.d.IsDeletionSuccesfull){
CloseDialog();
}
else{
AlertDialog(deletionResponse.d.Message);
}
}
The OnFailure will fire based off the status code of the result, so something like this would give the desired effect.
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "Reason for failure");
Also, not sure if it's related but shouldn't your OnFailure text be "AlertDialog" instead of "AlerDialog"?
EDIT: In your controller action you should be able to test that the request is being made via Ajax by using this Extension method MVC provides Request.IsAjaxRequest(). Note that there is no true way to check if a request is an Ajax request on the server, this method is utilizing the presence of a custom header jQuery sets for all ajax requests it makes, in other words don't use Request.IsAjaxRequest() in business logic.
Source for IsAjaxRequest() method
namespace System.Web.Mvc
{
public static class AjaxRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequestBase request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
return (request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest"));
}
}
}
how about throwing an exception?
public ActionResult DeleteConfirm(int id)
{
try
{
//make your call to the database here
return View();
}
catch (ExceptionType1 ex)
{
//log the details of your error for support purposes, alerting tracing etc.
ex.Message = "Nice message for user"
throw ex;
}
catch (ExceptionType2 ex)
{
//log the details of your error for support purposes, alerting tracing etc.
ex.Message = "Another nice message for user"
throw ex;
}
}
Your ajax call would then know it was a failure, and run the correct function.
I have a custom exception filter that I'm calling by virtue of adding a [CustomExceptionFilter] attribute to my class. It works as I'd like it to, however if the action method is returning a partial view (through an ajax request), the exception (which is basically a redirect to a not authorized page), is loading up the partial view with that page. Is there a way I can force it to reload the 'parent' url?
Here is the code for the custom exception filter
public class CustomExceptionFilter : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() == typeof(CustomSecurityException))
{
filterContext.ExceptionHandled = true;
RequestContext rc = new RequestContext(filterContext.HttpContext, filterContext.RouteData);
string url = RouteTable.Routes.GetVirtualPath(rc, new RouteValueDictionary(new { Controller = "NoAccess", action = "Index", message = filterContext.Exception.Message })).VirtualPath;
filterContext.HttpContext.Response.Redirect(url, true);
}
}
}
This is something you need to handle on the browser. Try handling the error() on jQuery.ajax() call for example (and obviously don't return redirect..).
I would suggest letting the exception bubble up to the client and handle it like Maxwell suggested.
In our previous project we used a specific actionfilter for handling ajax errors (borrowed from Suteki Shop). Note that the response status is 500 (internal server error). An error status is required for the response in order to call de Error() delegate within a JQuery.ajax() call.
public class HandleErrorWithAjaxAttribute : HandleErrorAttribute
{
public HandleErrorWithAjaxAttribute()
{
ShowStackTraceIfNotDebug = true;
}
public bool ShowStackTraceIfNotDebug { get; set; }
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
string content = ShowStackTraceIfNotDebug ||
filterContext.HttpContext.IsDebuggingEnabled
?
filterContext.Exception.StackTrace
:
string.Empty;
filterContext.Result = new ContentResult
{
ContentType = MediaTypeNames.Text.Plain,
Content = content
};
filterContext.HttpContext.Response.Status =
"500 " + filterContext.Exception.Message
.Replace("\r", " ")
.Replace("\n", " ");
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
else
{
base.OnException(filterContext);
}
}
}
I use the OnFailure hanlder in form tag.
<form id="AJAXForm" method="post" action=""
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'POST',
updateTargetId: 'myPartialPage', onSuccess: Function.createDelegate(this, ajaxFormSucced),
onFailure: Function.createDelegate(this, ajaxFormFailure) });" >
...
function ajaxFormSucced(){
// Code for success
}
function ajaxFormFailure(){
// Code for failure
}
You can verify if the request is an ajax request or not.
You could for example do the following...
if (!filterContext.HttpContext.Request.IsAjaxRequest()){
//Return a ViewResult
//filterContext.ExceptionHandled = true;
//filterContext.Result = new ViewResult { ViewName = "Error" ... };
}
else{
//An ajax request.
//return a partial view
}
However, as Maxwell said you could let the exeption bubble up if it is an ajax request and handle the error on the client. You can setup globally a way of handling exceptions in ajax requests like it is described here
Did you try clearing the response? The controller may still be setting response content.
filterContext.HttpContext.Response.Clear()
filterContext.Result = new JsonResult { Data = new { Message = message } };
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
This link helped me
Handling ASP.NET MVC exceptions when posting to the controller via Ajax using jQuery
Lastly, When testing the javascript function, start with alert on the first line. Any javascript errors in your function are likely to stop the function in mid execution without javascript error feedback via the browser (depending on your setup).
This will help you.
Just add .IsAjaxRequest extension method and return 403 status code to browser, jquery ajaxError will handle it redirecting to login page
As Maxwell says, handle on the client, using something like this
function handleError(ajaxContext) {
// Load parent
}
#using (Ajax.BeginForm("Index", "Home", new AjaxOptions
{
UpdateTargetId = "MyDiv",
OnFailure = "handleError"
}))
What you must do though is make sure in the controller ActionResult code for NoAccess contains the following code, so that your ajax error is triggered.
HttpContext.Response.StatusCode = 401;