Ajax calls stop working while using MVC Custom routes - ajax

I have defined custom routes for user friendly URLs.
But unable to call default route using ajax or on using Ajax.BeginForm() On removing custom routes, all works perfectly.
This is my RouteConfig.cs
//product view route
routes.MapRoute(
name: "ProductView",
url: "product/{product_name}/{id}",
new { controller = "Product", action = "View", product_name = UrlParameter.Optional, id = UrlParameter.Optional },
new[] { "NoveltyApp.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "NoveltyApp.Controllers" }
);
Product View URL: http://localhost:56379/product/Camlin-Kokuyo-Acrylic-Color-Box---9ml-Tubes-1/1
ProductController.cs
public string ProductReviews()
{
return "Product review list";
}
Ajax call from Product view
<button type="button" class="btn btn-thm nf-pr-vi__btn" onclick="reviews()">Reviews</button>
<script>
function reviews() {
$.ajax({
url: '/Product/ProductReviews',
type: 'GET',
success: function (data) {
alert(data);
}
});
}
</script>
But on click button controller action not getting hit. Please help me out with a solution.

Related

Url doesn't changing when redirecting to another action method in same controller

In myC# MVC project, i have a 'Home' controller like below,
Controller
public ActionResult Index()
{
return this.View();
}
public ActionResult LoadVideo()
{
return RedirectToAction("LoadVideoExt");
}
public ActionResult LoadVideoExt()
{
return this.View();
}
And my problem is, my url is like this http://localhost:51241/Home/Index when running the code. I have a button in my Index view to call LoadVideo from there I am redirecting to another action and load that page LoadVideoExt. The process is working fine but the final view is not rendering and also my url is not changing accordingly (as I am expecting http://localhost:51241/MyJob/LoadVideoExt). I am a bit confused here. Could someone help me out or point me in the right path?
Sample code attached below.
View (Index.cshtml)
function uploadMedia() {
linkUrl = '#Url.Action("LoadVideo", "Home", new { area = string.Empty })';
var formData = new FormData($('#fromIndex')[0]);
$.ajax({
url: linkUrl,
type: 'Post',
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function () { },
success: function (result) {
alert(0);
},
xhr: function () { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { // Check if upload property exists
// Progress code if you want
}
return myXhr;
},
error: function () {
}
});
}
RouteConfig.cs
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DefaultMultipleParams",
url: "{controller}/{action}/{id}/{state}"
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
View (LoadVideoExt.cshtml)
#{
ViewBag.Title = "LoadVideoExt";
}
<h2>Gotcha!</h2>
Let assume my url is like this http://localhost:51241/MyJob/Index when running the code. I have a button in my 'Index' view to call LoadVideo from there I am redirecting to another action and load that page LoadVideoExt. The process is working fine but the final view is not rendering and also my url is not changing accordingly (as I am expecting http://localhost:51241/MyJob/LoadVideoExt). I am a bit confused here. Could someone help me out or point me in the right path?

How to redirect from a url in MVC5

I have a url which says www.test.com/12345. When the user hit this url, he should be redirected to respective action method where "12345" accepts as its parameter.
I have a slight idea that can be used with RouteConfig but still no clear picture.
Can any one help me on this please?
Action method is
[HttpPost]
public ActionResult DetailsByCode(string code)
{
IEnumerable<IProductListDto> prdctListDto = _productListDetails.GetProductListByCode(accessCode);
Return "success";
}
and routeconfig is
routes.MapRoute(
name: "Accesscode",
url: "{Areas}/{controller}/{action}/{id}",
defaults: new { Areas = "Student", controller = "Student", action = "DetailsByCode", id = string.Empty }
);
My complete routeconfig.cs is
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DetailsByCodeRoute",
url: "{Areas}/{controller}/{action}/{id}",
defaults: new { Areas = "Student", controller = "Student", action = "DetailsByCode" }
);
routes.MapRoute(
name: "Accesscode",
url: "{Areas}/{controller}/{action}/{id}",
defaults: new { Areas = "Student", controller = "Student", action = "DetailsByCode", id = string.Empty }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "ChangePassword",
url: "{Areas}/{controller}/{action}/{id}",
defaults: new { Areas = "User", controller = "User", action = "ChangePassword", id = string.Empty }
);
routes.MapRoute(
name: "PasswordReset",
url: "{Areas}/{controller}/{action}/{id}",
defaults: new { Areas = "User", controller = "User", action = "PasswordReset", id = string.Empty }
);
In your situation you can use Route Constraints.
For example read this post.
http://www.c-sharpcorner.com/UploadFile/ff2f08/custom-route-constraints-in-Asp-Net-mvc-5/
Instead of adding new route i added one line in Routeconfig.cs which is for Enable Attribute routing.
routes.MapMvcAttributeRoutes();
and one line before the action method
[Route("{accesscode:int}")]

Method called a GET instead of POST

I have this 'POST' method
[HttpPost]
[System.Web.Mvc.ValidateAntiForgeryToken]
public HttpResponseMessage UpdateProfile(string sAppUser)
{
MobileProfileModel profileModel= JsonConvert.DeserializeObject<MobileProfileModel>(sAppUser);
using (ucApp = new UserControllerApplication())
{
//this code should match the
bool success = ucApp.UpdateUserProfile(profileModel);
var response = Request.CreateResponse<bool>(HttpStatusCode.Created, success);
string uri = Url.Link("DefaultApi", new { result = success });
response.Headers.Location = new Uri(uri);
return response;
}
}
and i calling it like this AJAX 'POST'
$.ajax({
url: "http://mydomain.com/api/User/UpdateProfile",
data:JSON.stringify(profile),
type: 'POST',
contentType: 'application/json',
//dataType: "json",
async: false,
cache: false,
success: function (data) {
$.blockUI({ message: "Success" });
},
error: function (xhr) {
alert(xhr.responseText);
},
beforeSend: function() {
$.blockUI({ message: $("#ajaxLoader") });
},
complete: function() {
$.unblockUI();
}
});
and im getting this error
<Error>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
The problem is Im not calling a GET method and the method isnt marked as a GET either. I am not sure what the issue is.
UPDATE
these are my route definitions
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//specific route for just the public views
routes.MapRoute(
"publicview",
"publicview/details/{userName}",
new { controller = "publicview", action = "details", username = UrlParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I am executing a Get method on the same controller and it works, this actually the post of that initial get.
There are two things here, firstly is there any reason why you have used full path in your ajax request and not absolute path ? Is this only for example purpose ? I would recommend you to you absolute path.
Next if you could try this in your ajax call, change the following
url: "http://mydomain.com/api/User/UpdateProfile",
to
url: "/api/User/UpdateProfile/" + profile,
Or else if you want to use the data: attribute in your ajax call use like this
data: {sAppUser: profile},
Let me know if this doesnt help.
i think there 2 are reasons for this error msessage:
your server uri routing routes your request to the wrong method
your ajax request are calling the wrong uri
if you want to be sure for calling POST look take a look via wireshark or try a different tool for post (e.g. curl)
UPDATE
your uri form AJAX reqeust is:
/api/User/UpdateProfile
your uri template is:
api/{controller}/{action}/{id}
I think you get this error because they don't match.
by the way: you should not use post for updating a profile, use PUT with an ID
for example:
$.ajax({
url: "/api/User/UpdateProfile/"+UserID,
data:JSON.stringify(profile),
type: 'PUT',
contentType: 'application/json',
//dataType: "json",
async: false,
cache: false,
success: function (data) {
$.blockUI({ message: "Success" });
},
error: function (xhr) {
alert(xhr.responseText);
},
beforeSend: function() {
$.blockUI({ message: $("#ajaxLoader") });
},
complete: function() {
$.unblockUI();
}
});
and in the controller:
[HttpPut]
[System.Web.Mvc.ValidateAntiForgeryToken]
public HttpResponseMessage UpdateProfile(string sAppUser) // I don't know how to parse the id from uri ;)
{
//find the user by his uniqe ID
MobileProfileModel profileModel= JsonConvert.DeserializeObject<MobileProfileModel>(sAppUser);
using (ucApp = new UserControllerApplication())
{
//this code should match the
bool success = ucApp.UpdateUserProfile(profileModel);
var response = Request.CreateResponse<bool>(HttpStatusCode.Created, success);
string uri = Url.Link("DefaultApi", new { result = success });
response.Headers.Location = new Uri(uri);
return response;
}
}

WebApi call fails for other than the default route

I have an Mvc3 project that includes both Mvc and Api controllers. When I run the application without specifying the "controller/action", the "Default" route is selected and the "home/index" page is rendered. When that page runs, an Ajax call is made using url: "api/controller", returning json, which is then used to populate a table on the page.
<script type="text/javascript">
$(function () {
var $products = $("#products");
$.ajax({
url: "api/products",
contentType: "json",
success: function (data) {
$.each(data, function (index, item) {
$products.append("<tr><td>" + item.ProductCode + "</td>" +
"<td>" + item.Description + "</td>");
});
}
});
});
</script>
However, when a request is made to the same page specifying the "controller/action", as in "localhost/home/index", the Ajax call is translated to "/home/api/controller" and of course the request cannot complete or return any results, since the ApiController cannot be found.
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Considering that it must be a routing issue, I proceeded to resolve this by adding a route:
routes.MapHttpRoute(
"HomeApi",
"home/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
This was successful. As was my next change to:
routes.MapHttpRoute(
"AnyApi",
"{folder}/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
Which also works but leaves me somewhat skeptical as to whether it is the correct way to handle combining WebApi with Mvc.
Is this the correct way to handle this? Or are there better alternatives?
Considering that it must be a routing issue, I proceeded to resolve this by adding a route:
No, that's not a routing issue at all. Your routes are perfectly fine:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Your issue stems from the fact that you have hardcoded the url in your javascript instead of using url helpers to generate it. You should absolutely never hardcode an url inside an ASP.NET MVC application. You should always use url helpers.
So:
<script type="text/javascript">
$(function () {
var $products = $("#products");
var url = '#Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" })';
$.ajax({
url: url,
success: function (data) {
$.each(data, function (index, item) {
$products.append("<tr><td>" + item.ProductCode + "</td>" +
"<td>" + item.Description + "</td>");
});
}
});
});
</script>
Also notice that I have removed the contentType: 'json' from your AJAX call because first the correct content type is contentType: 'application/json' and second in this case you are not sending any data in the request, so you shouldn't be setting it to application/json.
There's no need to add a route there -- you can specify the API URL so that it will always work:
/api/controller
In some cases you may need to use the Url.RouteUrl helper to create URLs explicitly based on the route (by route name and/or route values). For example, this would specify the route named "DefaultApi" with controller=products:
#Url.RouteUrl("DefaultApi", new { controller = "products" })

Ajax Post: 405 Method Not Allowed

Within my API Controller called Payment, I have the following method:
[HttpPost]
public HttpResponseMessage Charge(Payment payment)
{
var processedPayment = _paymentProcessor.Charge(payment);
var response = Request.CreateResponse(processedPayment.Status != "PAID" ? HttpStatusCode.ExpectationFailed : HttpStatusCode.OK, processedPayment);
return response;
}
In my HTML page I have:
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "http://localhost:65396/api/payment/charge",
data: $('#addPayment').serialize(),
dataType: "json",
success: function (data) {
alert(data);
}
});
Whenever I fire the POST, I get
"NetworkError: 405 Method Not Allowed - http://localhost:65396/api/payment/charge"
What am I missing?
Thank you.
UPDATE
Here's the routing information (default)
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Most likely your routing is not configured for the action to be invoked. Hence the request ends up in nowhere and ASP.NET Web API sends a blank-out message "method not allowed".
Can you please update the question with your routing?
UPDATE
As I thought! You are sending to http://localhost:65396/api/payment/charge while you need to send to http://localhost:65396/api/payment - assuming your controller is called PaymentController.
Note that route does not have action.
Turns out I needed to implement CORS support. http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/20/implementing-cors-support-in-asp-net-web-apis.aspx
I had the same problem with my controller.
The only thing which is different is the ending of the URL.
Add "/" to "http://localhost:65396/api/payment/charge" at the end, that helped me

Resources