MVC viewModel and paged results - c#

I have a need to pass into a controller a viewmodel as per below.
[HttpPost]
public JsonResult GetSearchResultsJson(SearchCriteria searchCriteria)
{
}
SearchCriteria is defined as:
public class SearchCriteria
{
public SearchData searchData { get; set; }
public SearchMode searchMode { get; set; }
}
Where SearchMode is:
public class Searchmode
{
public int? mode { get; set; }
public int? pageNumber { get; set; }
public int? pageSize { get; set; }
}
And SearchData has 61 properties that define what items are to search for.
public class SearchData
{
public string name {get;set;}
....
public int age {get;set;}
}
I populate an object using jQuery and pass that to the controller. .Net converts this object into an object of type SearchCriteria. All is working, but when the PagedListPager control is rendered, how do i emulate the jQuery used to create the object?
At the moment I have the following code:
#Html.PagedListPager(Model.DocumentsPaged, pageNumber => Url.Action("GetSearchResultsJson", XXXXXXXXXXXXXXXXXXXXXXX),pLRO)
And do not know what to put in the bit marked as XXXXXXXXXXXXXXXXXXXXXXX.
Within jQuery, I can modify the pageNumber property of the SerachMode object and this does provide me with the correct page, but it is precisely this property that I need to update within the Html.PagedListPager helper.

As described in example here you can pass the page.
I really suggest you to clone the example code and play a bit with it.
Probably you have to add your search parameters as well, in case you lose them server-side.

Your method GetSearchResultsJson(SearchCriteria searchCriteria) is marked [HttpPost], so you can leave the URL parameters blank and just use Url.Action("GetSearchResultsJson"). The search parameters for a POST go in the body of the request instead of the URL.
Because the Html.PagedListPager method expects a 'page' parameter (assuming you are using the method from the PagedList.Mvc NuGet package), you may want to write your search function like this:
GetSearchResultsJson(int page, int SearchCriteria searchCriteria)

Related

Controller accepting different models

I want to accept different model type from body based on query param value.
Example:
[HttpGet]
[Route("GetSystemdetails")]
public string Getdeatils([FromBody] SystemDetail sysdetails, string type)
{
//some code here
string details = getdetails(sysdetails);
}
// abc model
public class abc
{
public int UserID { get; set; }
public string Email { get; set; }
}
//xyz model
public class xyz
{
public int xyzid { get; set; }
public string systemval { get; set; }
public string snum { get; set; }
}
type abc and xyz will have it's own model. So based on type I receive in query param I wanted to pick the model and proceed.
Sample url:
localhost/GetSystemdetails/type=abc
localhost/GetSystemdetails/type=xyz
I thought of creating a new model SystemDetail which holds these two models(xyz and abc) and based on system pick them.
I wanted to know what are possible ways to achieve this kind of requirements without creating multiple methods in controller(I don't want to change the format of the URL).
That's not something that's supported out of the box. Your linked solution is probably the closest you'll get to that.
ASP.NET Core is not supposed to take values of the parameters into account when routing, except for validation.
There are several possible ways to do so
Having multiple model objects
As in the link you provided, you can declare multiple model objects. The site has given the example of
public class PostUserGCM
{
public User User { get; set; }
public GCM GCM { get; set; }
}
but you can use your own examples.
Base model
Your models can inherit from some base model. If you only need a single model at a time and they share some similarities, then you could just create a base model which the other two are inheriting from, be agnostic at implementation time and your use cases will mainly differ on instantiation inside the controller, while some service methods could handle other differences.

ASP.NET Core querystring object

I have a method called in get that receive in input (from the query string) some parameters that represent an object:
public override async Task<IActionResult> Index([FromQuery]MyFilter filter)
{
...
}
public class MyFilter : BaseFilter
{
public List<string> Rules{ get; set; } = new List<string>();
public string SearchString { get; set; }
}
If I call my method with this query string the property Rules is empty:
?filter.SearchString=&filter.Rules[]=foo&filter.Rules[]=bar
but if I call it with this query string, the property Rules is filled correctly:
?filter.SearchString=&filter.Rules[0]=foo&filter.Rules[1]=bar
So the field "Role"s is a html select so when user fill this field I do not know indexes.
Does someone have the same problem (and a solution for it)?
I think its better to use:
?SearchString=&Rules[]=foo&Rules[]=bar

Class type object as HttpGet

I am trying to create an action that would look like controller/action?param1=val&param2=val with the HttpGet annotation.
What I have is:
[HttpGet]
public IActionResult Index(SomeClass obj)
{
// do stuff
return View(something);
}
I can access the action via controller/Index?obj.param1=val&obj.param2=val, but is there a way to avoid obj.param1 and obj.param2 in the query string and have something like controller/Index?page=val&amount=val.
Putting those parameters in the annotation like this didn't work: [HttpGet("/page={obj.subobject.param1}&amount={obj.subobject.param2}")]
Assuming the default model binding setup, you can just pass the parameter names directly and ASP.NET Core will automatically put the values into the SomeClass object:
public IActionResult Test(SomeClass obj)
{
return Json(obj);
}
public class SomeClass
{
public string Foo { get; set; }
public string Bar { get; set; }
}
When opening the URL /Home/Test?foo=baz&bar=qux you will now see that the object is properly filled with the Foo and Bar properties.

Getting different result from an mvc action method

I have a business layer that has some IEnumerable methods. I used those methods in my controller and get result after make methods result to .ToList().
Now there is a new requirement. I have to filter action result data per user access. When users call an action method, only one business layer method called, but I need different result per user. For example: user A can load all data but user B only access 10 rows data according by his permission.
Code:
BL:
public IEnumerable<Card> GetCardList(int Id)
{
return unitOfWork.GetCardList(Id);
}
Controller:
//...
CardBl.GetCardList(id).ToList();
//...
I tried to filter data in a CustomActionFilter class by overriding OnActionExecuting or OnResultExecuting methods, but I'm confused!
Actually I want to make this kind of filtering automate by attributes instead of adding where clause for every method.
I would appreciate if anyone suggest a solution.
Update:
My Model:
public class CardModels
{
public int Id { get; set; }
public string CardName { get; set; }
public string CardDescription { get; set; }
public int CityId { get; set; }
}
CityId is the property that I have to filter data based on.

MVC Model Class not populated on post

I have two MVC models that look like this:
public class OtherModel
{
[Required]
[Display(Name = "Another ID")]
public int id{ get; set; }
}
public class MyModel
{
[Required]
[Display(Name = "ID")]
public int id { get; set; }
public PlayerModel otherModel = new OtherModel ();
}
My controller has an [HttpPost] action called USE that looks like this:
[HttpPost]
public ActionResult Use(MyModel myModel)
{
/// myModel.otherModel.id is 0 here!!
}
This action takes in a MyModel. When my form is being posted, the otherModel variable contains a 0 for the id value. Now, the view that contains the form is handed a MyModel and actually displays the otherModel.id on the page. The problem is the post action is not
properly marshalling the form data into the otherModel object and I have no clue why.
Another note: When I examine the form data headers for the post, I clearly see otherModel.id with the value that I expect.
Why is this data not appearing correctly within my otherModel object?
Thank You in advance!
Did you registered binder in Global.asax.cs?
public static void RegisterBinders(ModelBinderDictionary binders)
{
binders.Add(typeof(MyModel), new MyModelBinder());
// other binders
}
This is called in Application_Start like the following:
protected void Application_Start()
{
RegisterBinders(ModelBinders.Binders);
}
PS: I assumed you are using a custom model binder. In case you are using automatic binding see if you respect the naming conventions.
Instead of initializing otherModel with a new object at the line PlayerModel otherModel = new OtherModel();, use a property public PlayerModel otherModel { get; set; }. otherModel needs a property setter for the model binder to assign the value properly. This may require you to also change how you populate the otherModel property when displaying the view - construct an object and assign it explicitly in either the displaying controller method or some other function that hydrates the model.
I had an almost identical issue. The fix for me was as Matt mentioned, to make the inner object a property with the needed accessors.
public class OuterModel
{
public OuterModel ()
{
AuxData= new InnerModel();
}
public InnerModel AuxData{ get; set; }
}
public class InnerModel
{
Int Id {get; set;}
}

Categories