MVC4 web api model not binding when called from angularjs - c#

I have a action method with this signature:
public List<Member> Get([FromUri]MemberSearchModel searchModel)
The model looks like this:
public class MemberSearchModel
{
public string SearchBy { get; set; }
public string SearchValue { get; set; }
}
and im calling the api like this:
dataFactory.getMembers = function () {
var memberSearchModel = {
SearchBy: 'Name',
SearchValue: 'jaredites'
};
return $http.get(urlBase, memberSearchModel);
};
the method is hit but the model comes through with null values
Ive tried not using [FromUri] but then the model itself is null
Ive tried [FromBody] and the model comes through as null as well.
Is there something Im missing here?
It works when I call it specifying the params in the url

Please try this that :
dataFactory.getMembers = function () {
var memberSearchModel = {
SearchBy: 'Name',
SearchValue: 'jaredites'
};
return $http.get(urlBase, {params: memberSearchModel});
};

Related

MVC5 WebApi 2 create not getting value from body ([FromBody])

I created a simple create Web API 2 action that will get an object from the post body and then will set it to the DAL layer. However no matter what I do using postman to get the object into the method, it always stays null.
The model looks like this:
namespace WebApi.Models
{
using System;
using System.Collections.Generic;
public partial class Classes
{
public int Id { get; set; }
public string ClassName { get; set; }
public int MaxStudents { get; set; }
}
}
My controller is as follows:
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj)
{
if (classObj == null)
{
return BadRequest("missing parameters.");
}
var newClass = new Classes()
{
ClassName = classObj.ClassName,
MaxStudents = classObj.MaxStudents
};
_context.Classes.Add(newClass);
_context.SaveChanges();
var newClassUrl = Url.Content("~/") + "/api/classes/";
return Created(newClassUrl, newClass);
}
Now when I use postman I tried two options.
option 1:
URL: http://localhost:53308/api/classes/
Headers: Content-Type: applications/json
[
"classObj": {
ClassName = "test"
MaxStudents = 100
}
]
option 2:
URL: http://localhost:53308/api/classes/
Headers: Content-Type: applications/json
ClassName = "test"
MaxStudents = 100
but in both cases classObj stays empty and it returns "missing parameters.". So obviously I'am missing something here.
What am I doing wrong?
Your payloads do not match the expectation of the action.
For example
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj) {
//...
}
Would expect JSON data that looks like this
{
"ClassName": "test"
"MaxStudents": 100
}
Also given that the model posted into the action is the same type added to the store there isn't really a need to create a new instance.
[HttpPost]
public IHttpActionResult CreateClass([FromBody] Classes classObj) {
if (classObj == null) {
return BadRequest("missing parameters.");
}
_context.Classes.Add(classObj);
_context.SaveChanges();
var newClassUrl = Url.Content("~/") + "/api/classes/" + classObj.Id.ToSTring();
return Created(newClassUrl, classObj);
}

Change URL Routing by overriding GenericPathRoute.cs in Plugin nopCommerce 3.3

I am trying to create a plugin which will override the TopicsDetails.cshtml page. I added a route like this:
routes.MapRoute("Nop.Plugin.Other.CustomTopic.ViewCustomTopic", "{SeName}",
new { controller = "CustomTopic", action = "TopicDetails", SeName = UrlParameter.Optional },
new[] { "Nop.Plugin.Other.CustomTopic.Controllers" });
This is getting all the {SeName} to my CustomTopicController .Even the products SeName.
If I add this instead of the older one:
routes.MapRoute("Nop.Plugin.Other.CustomTopic.ViewCustomTopic",
new { controller = "CustomTopic", action = "TopicDetails" },
new[] { "Nop.Plugin.Other.CustomTopic.Controllers" });
I get an error because the TopicDetails(int itemId) Action receives an integer which is not provided as we know that GenericPathRoutes.cs Provides that integer.
How can I override the Rules of GenericPathRoutes.cs to do it so that only the topic SeName would hit my Controller or is there other way to do that kind of work or is it even possible to do?
Recently i wrote an article which shows how to override localized route and i used the TopicDetails view as an example. There article is here.
Inshort, your route provider shall look like this;
public class RouteProvider : IRouteProvider
{
private const string NAMESPACES = "Nop.Plugin.Misc.Custom.Controllers";
private const string CONTROLLER = "MiscCustom";
public void RegisterRoutes(RouteCollection routes)
{
//Public Override
routes.MapGenericPathRoute("Plugin.Misc.Custom.GenericUrl",
"{generic_se_name}",
new { controller = "Common", action = "GenericUrl" },
new[] { NAMESPACES });
}
public int Priority
{
get { return Int32.Max; }
}
}
I am not sure whether i understand your question
can you try it by adding
id = UrlParameter.Optional
here any id parameter is optional it wont throw that error

Web API Complex and primitive parameters in one action

I have an ASP.NET Web API action:
[HttpPost]
public void test(myCustomObj Entity)
{
}
And the JSON data is:
{
"ID": "1",
"Name": "ilhan",
"surname": "aksu"
}
So far my code works well. However, when I add a new primitive parameter:
[HttpPost]
public void test(myCustomObj Entity, [FromBody] string strdata)
{
}
and when I post the following JSON:
{
"Entity": {
"ID": "1",
"Name": "ilhan",
"surname": "aksu"
},
"strdata": "testdata"
}
the server returns 500 Internal Server Error.
How can I format my JSON data or change my action method to fix this problem?
If you're posting json, you could accept a string parameter:
[HttpPost]
public void Test(string jsonString)
{
}
And maybe a serializer helper to avoid polluting the code:
public static class JsonSerializer
{
public static string Serialize<T>(T t) where T : class
{
return JsonConvert.SerializeObject(t);
}
public static T Deserialize<T>(string s) where T : class
{
return (T)JsonConvert.DeserializeObject(s, typeof(T));
}
}
Then in your method you can materialize the json payload:
[HttpPost]
public void Test(string jsonString)
{
var o = JsonSerializer.DeserializeObject(jsonString, typeof(MyObject));
// ...
}
And if you're returning json, it could be as follows:
[HttpGet]
public JsonResult GetTest()
{
var i = YourService.GetSomethingById(1);
iSerialized = JsonSerializer.Serialize(i);
return new JsonResult
{
ContentEncoding = System.Text.Encoding.UTF8,
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = iSerialized
};
}
As always write a view model
public class MyViewModel : myCustomObj
{
public string Strdata { get; set; }
}
Now have your controller action take this view model as argument:
[HttpPost]
public void test(MyViewModel model)
{
...
}
and now you could hit your action with the following JSON payload:
{"ID":"1","Name":"ilhan","surname":"aksu","strdata":"testdata"}
and everything's gonna get properly bound.
Alternatively your view model might look like this:
public class MyViewModel
{
public myCustomObj Entity { get; set; }
public string Strdata { get; set; }
}
and now you could hit your action with this payload:
{"Entity":{"ID":"1","Name":"ilhan","surname":"aksu"},"strdata":"testdata"}
So it's basically up to you to decide how your view model will look like depending on the JSON payload that you would like to use to call your controller action. So, never think of having more than 1 action argument in a controller action. Always think in terms of how your view model will look like.
Yes, controller actions always take view models as arguments and always return view models. That's the correct design. In ASP.NET MVC and in ASP.NET Web API.

What is the use case for using a JsonResult action in asp.net mvc3?

When is it typical to use the JsonResult action in an ASP.NET MVC 3 application?
From where is the JsonResult usually called; from another action or an actionlink rendered in the html?
Can you give me some examples where you want json instead of a typical view?
Say, for example you wanted to populate a jQuery autocomplete with a list of values based on a selection of another field, so you can't determine the data on page load. I would typically call an action method in a $.ajax call, then return an array of items to populate the autocomplete with.
Example, here's my jQuery, one function for the call and another that gets called to populate the automcomplete with received data:
$(function() {
$.ajax({
url: '#Url.Action("GetHomes", "Account")',
type: "POST",
datatype: "json",
success: function (data) {
if (data.Success || data.Success == null) {
WireUpHomesData(data);
} else {
ShowErrorDialog();
}
}
});
ShowDialog();
});
function WireUpHomesData(data) {
var homes = new Array();
for (var i = 0; i < data.length; i++) {
homes[i] = { label: data[i].HomeName, text: data[i].HomeId, icon: data[i].HomeIcon, desc:data[i].HomeAddress };
}
$("#home").autocomplete({
source: homes,
select: function (event, item) {
homeUrl = '#Url.Action("Site", "Sites")/' + item.item.text;
}
}).data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a><span class='" + item.icon + "'/><span class='fs-ui-autocomplete-home'>" + item.value + "</span><br>" + item.desc+ "</a>")
.appendTo(ul);
};
$(".ui-autocomplete").addClass("fs-ui-autocomplete");
}
And here is my controller:
public JsonResult GetHomes()
{
return Json(RequiresAclAttribute.HomesForUser());
}
And here's the method signature for the method that's called:
public IEnumerable<HomeInfo> HomesForUser()
And for clarity, here's the HomeInfo class:
public class HomeInfo
{
public string HomeId { get; set; }
public string HomeName { get; set; }
public string DisplayName { get; set; }
public string HomeAddress { get; set; }
public string HomeIcon { get; set; }
}
JsonResult is a subclass derived from ActionResult class. You can use this when you want to return a Json object.
public JsonResult GetItems()
{
var jsonResult=new { Id = "23", Name = "Scott"};
return Json(jsonResult,JsonBehaviour.AllowGet);
}
This will return the same result as
public ActionResult GetItems()
{
var jsonResult=new { Id = "23", Name = "Scott"};
return Json(jsonResult,JsonBehaviour.AllowGet);
}
Possible use of this is to get some chunk of data in asynchronous way. Ex : Imagine you have a drop down where you are showing the states and when user selects a state, you want to to bring the list of cities belongs to the state and show it in the page without a page refrest. you can call use jQuery ajax /getJson method (short hand of jQuery get with json as datatype) method to get this data from an ActionMethod which returns Json data.
A small example to call an Action method which returns the Json data
$(function(){
$.getJSON('YourController/GetItems', function(data) {
alert(data.Id);
alert(data.Name );
});
});
With JsonResult class the response content type will be "application/json" if nothing is specified explicitly. Internally The ExecuteResult method uses JavaScriptSerializer to Serialize the content when returning data.
The JsonResult is very usefull wehn making ajax calls from javascript, e.g. using getJSON from jQuery: http://api.jquery.com/jQuery.getJSON/
The benefit of JsonResult is it returns a JSON formatted result without effort.
An Ajax request from a client script that does not involve a full page load. Basically.
Whenever there is client side processing and client need that data use jsonresult like in autofill or remote validation

Route/view binding issue with MVC3/Razor

In my MVC3 application, I have an action that routes to a custom action depending on an object selected.
public ActionResult SearchCityState(string city, string state, string searchTerm)
{
city = Server.HtmlEncode(city);
state = Server.HtmlEncode(state);
searchTerm = Server.HtmlEncode(searchTerm);
// now build the search object
...
return DoSearch(sourceRequestObject);
}
public ActionResult SearchState(string state, string searchTerm)
{
state = Server.HtmlEncode(state);
searchTerm = Server.HtmlEncode(searchTerm);
// now build the search object
...
return DoSearch(sourceRequestObject);
}
Those two methods do a bit of work in populating an object and calling the following DoSearch() method in the class and are selected based on some logic:
public ActionResult DoSearch(FeederService.SearchRequestObject sourceRequestObject)
{
...
var model = new MyAppMVC.Models.ResultsModel();
var page = model.GetData(sourceRequestObject);
return View(page);
}
Here's my model class:
public class ResultsPage
{
public DataSet dsResults { get; set; }
public Int32 actualNumberOfResults { get; set; }
public int numberOfResultsReturned { get; set; }
}
public class ResultsModel
{
...
public ResultsPage GetData(FeederService.SearchRequestObject sourceRequestObject)
{
var page = new ResultsPage();
...
page.dsResults = myWcfFeederClient.GetData(sourceRequestObject);
if (page.dsResults != null)
{
page.actualNumberOfResults = Convert.ToInt32(page.dsResults.Tables[1].Rows[0]["ActualNumberOfResults"].ToString());
page.numberOfResultsReturned = Convert.ToInt16(page.dsResults.Tables[1].Rows[0]["NumberOfResultsReturned"].ToString());
}
return page;
}
}
I have a view defined in /Results/SearchResults.cshtml that I want to route all requests to, as the output will be the same for all
The issue is that the initially selected action name is the default selected view. ie. if SearchCityState() is called, the following exception is thrown:
The view 'SearchCityState' or its
master was not found or no view engine
supports the searched locations. The
following locations were searched:
~/Views/Results/SearchCityState.aspx
~/Views/Results/SearchCityState.ascx
~/Views/Shared/SearchCityState.aspx
~/Views/Shared/SearchCityState.ascx
~/Views/Results/SearchCityState.cshtml
~/Views/Results/SearchCityState.vbhtml
~/Views/Shared/SearchCityState.cshtml
~/Views/Shared/SearchCityState.vbhtml
... and similar for SearchState(). I'm familiar with this issue, but I can't recall how to route all requests to that one view.
Thanks.
UPDATE
Here are the routes I have defined:
routes.MapRoute(name: "CityHomePage", url: "{city}-{state}", defaults: new { controller = "Home", action = "GeoHomePage" });
routes.MapRoute(name: "CityStateResults", url: "{city}-{state}/{searchTerm}", defaults: new { controller = "Results", action = "SearchCityState" });
... and off of a link defined as:
My CityState Link
I'm ending up with the following error:
The view 'SearchCityState' or its
master was not found or no view engine
supports the searched locations. The
following locations were searched:
~/Views/Results/SearchCityState.aspx
~/Views/Results/SearchCityState.ascx
~/Views/Shared/SearchCityState.aspx
~/Views/Shared/SearchCityState.ascx
~/Views/Results/SearchCityState.cshtml
~/Views/Results/SearchCityState.vbhtml
~/Views/Shared/SearchCityState.cshtml
~/Views/Shared/SearchCityState.vbhtml
Use another overload of the View() method, which takes the view name as the 1st parameter:
public ActionResult DoSearch(FeederService.SearchRequestObject sourceRequestObject)
{
...
var model = new MyAppMVC.Models.ResultsModel();
var page = model.GetData(sourceRequestObject);
return View("SearchResults", page);
}
(The MSDN article isn't helpful, but the answer doesn't feel complete)

Categories

Resources