Pass Multiple params in ASP.NET MVC - asp.net

First of all, I'm still a beginner in MVC
Obviously anyone knows that we can pass by /CONTROLLER/METHOD/ID, but in some cases, like I need to pass 3-4 params into the controller, how should I do? Is there a good way of passing them all?
The code below is a controller dealing with post request, why I cannot use the "temp1"? it said that one should be declared before use, what that means?
[HttpPost]
public ActionResult Payment_Home(Wires_SWIFT temp1){
string str = temp1.BENEFICIARY_NAME;
DbQuery<Wires_SWIFT> dbq = db.Wires_SWIFT.Where(d => d.BENEFICIARY_NAME LIKE temp1.);
return View();
}

Use a ViewModel.
This is a class that contains all the values you need - you populate it in the controller action and pass it in to the view (helps if the view is strongly typed to the model.
public class MyModel
{
public string SomeValue { get; set; }
public string SomeOtherValue { get; set; }
}
// controller
var myModel = new MyModel...
return View(myModel);
// view
#model MyModel
#Model.SomeValue

You need to make sure you have a route set correctly.
so to match dothis/action/param1/param2 you'd want a route like:
routes.MapRoute(
"MyRoute", // Route name
"{controller}/{action}/{param1}/{param2}", // URL with parameters
new { controller = "Surveys", action = "Index", param1 = "param1", param2 = "param2" } // Parameter defaults
);
For the above route to actually work, you'll need a controller and action such as
public class DoThisController : Controller
....
public ActionResult Action(int param1, int param2)
....
The type of the action parameters doesn't matter, but the name should match the name defined in the rule to allow the action to be located by ASP.Net
In your case, the error is because your parameter is called temp1 & in the route data there is nothing called that.

Related

How to create a basic web api to get data

Trying to create a basic web api for my database table where anyone can view my table data using a URL (JSON format?). My understanding is that I should be able to get my data by typing in table name in URL.
my database table name is myTable which is mapped to model class My_Model
Issue: There are no errors but when i try to type in url https://localhost:7048/myTable/ it return page not found
[Route("[controller]")]
[ApiController]
public class My_Controller : Controller
{
public My_Services _services { get; }
public My_Controller(My_Services services)
{
this._services = services;
}
// Database Table Name = "myTable"
[HttpGet]
public IQueryable<My_Model> Get()
{
return (IQueryable<My_Model>)_services.Get_All_Data();
}
public IActionResult Index()
{
return View();
}
}
My_Services class - where get all data from table
public async Task<IQueryable<My_Model>> Get_All_Data()
{
IQueryable<My_Model> Query = from x in _context.My_DbSet
select x;
return Query;
}
My understanding is that I should be able to get my data by typing in
table name in URL.
No, this is not how it works. You should check Routing to controller actions in ASP.NET Core. In your example you should be able to access your data using this url: https://localhost:7048/My_. The reason is that your controller has the attribute [Route("[controller]")]. [controller] is a special value which means that the route should be the controller class name without the Controller suffix so My_ in this case.
If you want to have access using this url: https://localhost:7048/myTable then you need to either change the attribute to this: [Route("myTable")] or to change the controller class name to MyTableController.
Also your Get method looks wrong. You should await the _services.Get_All_Data method instead of casting to IQueryable<My_Model>:
[HttpGet]
public async Task<IQueryable<My_Model>> Get()
{
return await _services.Get_All_Data();
}

How do you require certain properties from the URI of the request?

I have a very simple model:
public class FoobarGETRequestModel {
[Required]
public string Id { get; set; }
}
It's being used for binding like so:
[HttpGet]
[ValidateModel] //This is a custom attribute for handling validation errors
public async Task<HttpResponseMessage> Foobar([FromUri]FoobarGETRequestModel model) {
...
}
If I make a request to /api/controller/foobar (notice I'm not providing an Id parameter), the ModelState.IsValid property always returns true (from both an action filter and from within the method above).
How do I bind via the URI and still leverage the frameworks ModelState validation?
Edit: Here is what ValidateModel looks like:
if (actionContext.ModelState.IsValid == false) {
var responseObject = new FooApiExceptionResponse() {
Errors = actionContext.ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage)
};
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, responseObject);
}
Did you check your RouteTable? If you are telling routetable that your "id" parameter is optional in default route, this could occur.

Asp.Net MVC 5 bind parameter exclusively from body

I want to prevent posting sensitive data via url query string to a MVC 5 application.
In MVC there is a DefaultModelBinder. The DefaultModelBinder looks for the ActionMethod parameters in the url query string, the body and the route. But my target is to bind the parameters exclusively from the body and not from route or query string.
In Asp.Net WebApi there is such a concept. The Attribute [FromBody] will do the job: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
Is there something suitable for MVC?
I´ve found the System.Web.ModelBinding.FormAttribute (https://msdn.microsoft.com/en-us/library/system.web.modelbinding.formattribute(v=vs.110).aspx). However, if I decorate the parameter, it has no effect to the model binding.
By default, the binder looks for data in four places: form data, route data, the query string, and any uploaded files.
It is possible to restrict the binding to a single source of data. To do so you should call the UpdateModel method passing, as the second parameter, a FormValueProvider object( an implementation of IValueProvider).
public ActionResult Products()
{
IList<Products> products = new List<Products>();
UpdateModel(products, new FormValueProvider(ControllerContext));
return View(products);
}
The complete list of objects is (they all receive the ControllerContext as the contructor parameter):
FormValueProvider: search for data in the body (Request.Form)
RouteDataValueProvider: search for data in the route (RouteData.Value)
QueryStringValueProvider: search for data in the query string (Request.QueryString)
HttpFileCollectionValueProvider: search for uploaded files (Request.Files)
Another way: create a custom model binder that uses FormValueProvider. The advantage of this is that you don't have to modify the action method.
Example:
[ModelBinder(typeof(PersonBinder))]
public class Person
{
[DisplayName("Social Security Number")]
public int SSN { get; set; }
[HiddenInput(DisplayValue = false)]
public string ShouldNotBind { get; set; }
}
public class PersonBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bindingContext.ValueProvider = new FormValueProvider(controllerContext);
Person model = (Person)bindingContext.Model ?? new Person();
model.SSN = Convert.ToInt16(GetValue(bindingContext, "SSN"));
return model;
}
private string GetValue(ModelBindingContext context, string name)
{
ValueProviderResult result = context.ValueProvider.GetValue(name);
if (result == null || result.AttemptedValue == "")
{
return "<Not Specified>";
}
return result.AttemptedValue;
}
}
And your action method:
[HttpPost]
public ActionResult Person(Person person)
{
return View(person);
}
Even if you post with a querystring, the ShouldNotBind property will show as "null".
Why not use form's then?
On submit you post form data

Extract controller and action names from ActionResult

In my view (or partial view), I want to use a helper that has this signature:
// using T4MVC to get the ActionResult from "MVC.FooController.BarAction()"
#Html.doStuff(MVC.FooController.BarAction(), someData)
instead of
#Html.doStuff(controllerName, actionName, someData)
I want to simplify my extension method, i.e. one argument instead of two.
In the extension method, how would I extract controller and action names from an instance of ActionResult?
Note that HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString(); doesn't help. I need to pass in an arbitrary ActionResult. So this is NOT a duplicate question
In View use below code -
#ViewContext.RouteData.Values["Controller"]
#ViewContext.RouteData.Values["Action"]
In Controller -
Request.RequestContext.RouteData.Values["controller"].ToString()
Request.RequestContext.RouteData.Values["action"].ToString()
In C# Helper Class -
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString();
If you want you retrieve Action and controller names from ActionResult, then one option would be -
// In Action
ViewBag.Controller = Request.RequestContext.RouteData.Values["controller"].ToString();
ViewBag.Action = Request.RequestContext.RouteData.Values["action"].ToString();
Then retrieve values from ActionResult in following way -
var controllerName = actionResultVariable.ViewBag.Controller;
var actionName = actionResultVariable.ViewBag.Action;
EDIT: Option 2 :
Create a Custom ActionResult -
public class MyActionResult : ViewResult
{
public MyActionResult(object model)
{
this.ViewData.Model = model;
}
public string ControllerName
{
get
{
return HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
}
}
public override void ExecuteResult(ControllerContext context)
{
base.ExecuteResult(context);
}
}
And then in your Controller Action -
return new MyActionResult(model);
Then as you are passing the ActionResult to your Extension method, you can use -
MyActionResultVariable.ControllerName

ASP.NET MVC3: can Action accept mulitple model parameters?

For example:
class MyContoller
{
[MyCustomAttribute]
public ActionResult MyAction(ModelX fromRequest, ModelY fromSession, ModelZ fromCookie)
{
string productId = fromRequest.ProductId;
string userId = fromSession.UserId;
string cultureName = fromCookie.CultureName;
}
}
Reason:
I don't want to visit Request, Session and HttpContext in the controllers, and the default idea of MVC3 which passing models to actions is very great.
I want the number of parameters of MyAction is easy to change. For example, if I add a new parameter, the system will try to look for values in Request, Session or Cookies by the name or type of the parameter (I think custom ModelBinders may be required for cookie values) and pass the filled model to my action. I don't have to write extra code.
Can the custom attribute (MyCustomAttribute in the example) accomplish this idea?
I am not sure I follow you about the custom attribute. What are you expecting the custom attribute to do?
Yes, an action method can take as many model parameters as you want. Obviously, only one can be bound in any given request (because a view can only have one model). Whichever one is found first will be bound, and the others will be null.
So let's say you have the following:
public class ModelX {
public string X {get;set;}
}
public class ModelY {
public string Y {get;set;}
}
public class ModelZ {
public string Z {get;set;}
}
And you have an action method like this:
public ActionResult DoIt(ModelX x, ModelY y, ModelZ z)
{
return View();
}
And in your DoIt.cshtml you have the following:
#model ModelZ
#using(Html.BeginForm()) {
#Html.TextBoxFor(x => x.Z)
<input type="submit"/>
}
If you type something into the textbox and submit, then the model binder will bind a ModelZ with the value you entered and ModelX and ModelY will be null.
If you mean can an action method bind multiple models simultaneously, then I would have to ask you.. How exactly do you plan to have a view have more than one model? You can certainly create a wrapper model to contain the multiple models, but a view can only have one.
Create a composite ViewModel class that incorporates ModelX, ModelY and ModelZ. You can then populate an instance of your new ViewModel class, and pass that to your controller method.
public class XYZViewModel
{
public ModelX fromRequest { get; set; }
public ModelY fromSession { get; set; }
public ModelZ fromCookie { get; set; }
}
public class MyController
{
[MyCustomAttribute]
public ActionResult MyAction(XYZViewModel myModel)
{
string productId = myModel.fromRequest.ProductId;
string userId = myModel.fromSession.UserId;
string cultureName = myModel.fromCookie.CultureName;
}
}
You can always pass multiple parameters to your controller action, yes. The key is to make sure they are properly serialized in the request. If you're using a form, that means using the Html helper methods.
For example, let's say you want an action like this:
public ActionResult Multiple(ModelA a, ModelB b)
{
// ...
}
You could create simple partial view for each model:
#model MyProject.Models.ModelA
#Html.EditorForModel()
Then in your Multiple view, render the partial views like so:
#{ using (Html.BeginForm("Multiple", "MyController", FormMethod.Get))
{
#Html.Partial("A", new MyProject.Models.ModelA())
#Html.Partial("B", new MyProject.Models.ModelB())
<input type='submit' value='submit' />
}
I set the method to GET here so that you can easily see how MVC passes the parameters. If you submit the form, you'll see that MVC successfully deserializes each object.

Resources