I have to work with queries like:
Controller/Action?query ={"action":"test","id":"13037313353","pin":"452312"}
by GET.
My ViewModel:
public class ValidatePinViewModel
{
public ActionType action { get; set; }
public int Id { get; set; }
public int Pin { get; set; }
}
Controller
public JsonResult ValidateVisit(CommonViewModel model)
{
//model is null
return Json(new InvalidPin());
}
Now I got null for my view. How I can get the correct model
As there is very little supportive information on this question, I'm going to take a shot and say that you're not POSTING to an action. e.g.
[HttpPost] // <-- Make sure you define your POST action
public JsonResult ValidateVisit(CommonViewModel model)
{
...
}
A GET, as you speficy in your tags, is not going to post a model. Unless you are specifically denoting it both in where you define your form element as well as on the action itself, it will be null.
I could add a string to get object.
Something like:
public JsonResult ValidateVisit(string query)
{
ValidatePinViewModel model = Json.Deserialize<ValidatePinViewModel>(query);
return Json(new InvalidPin());
}
Related
I have created a controller method similar to
[HttpPost]
public ActionResult<MyDTO> Post([FromBody] MyDTO myDTO)
{
// do something with myDTO...
Ok();
}
and MyDTO:
namespace MyNamespace.DTO
{
public class MyDTO
{
[Required]
public int someNumber { get; set; }
[Required]
public bool someBool { get; set; }
[Required]
public DateTimeOffset someDate { get; set; }
}
}
When I send a post with a JSON body that doesn't have either defined, instead of returning a 400 or an exception of some sort, it just assigns default (falsy) values to them.
When I defined a List of another DTO class, it did return a 400 code.
How can I make the API return an error when certain required values are not provided instead of just using default values?
You have to manually control it. There's no other way.
Try something like
[HttpPost]
public ActionResult<MyDTO> Post([FromBody] MyDTO myDTO)
{
if(YourComprobation(myDto)){
BadRequest();
}
Ok();
}
Found an answer here.
I just had to make all the fields nullable and have a
if (!ModelState.IsValid)
// return 400
in the controller.
I would like to know if I am doing something wrong or it is not possible to post only part of view model using default model binder. Let's say I have a complex viewmodel that only small part it should be posted. I would like to achieve something like this:
public class ComplexViewModel
{
public object FirstNotPostedData { get; set; }
public object SecondNotPostedData { get; set; }
//......
public object NthNotPostedData { get; set; }
public InnerModelToPost InnerModelToPost { get; set; }
}
public class InnerModelToPost
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
public string ThirdProperty { get; set; }
}
In view I would like to display part of model and post the other part:
#model ComplexViewModel
#* DISPLAYING DATA *#
<form>
#Html.HiddenFor( m => m.InnerModelToPost.FirstProperty )
#Html.HiddenFor( m => m.InnerModelToPost.SecondProperty )
#Html.HiddenFor( m => m.InnerModelToPost.ThirdProperty )
<button type="submit">Submit button</button>
</form>
And then I would like to be able to pass this model to my controller in this way using default model binder:
public ActionResult GetOnlyImportantPartOfModel( InnerModelToPost innermodel)
{
//I'm getting empty model when I' doing like this
return View();
}
You may ask why not to pass entire model as parameter to this action method. So the answer is: code readablity. I store ComplexViewModel in session and I read it in first line of my action method. I would like to pass only this data that I want to update my model with.
Your need to use the Prefix property of [Bind] attribute to strip the InnerModelToPost prefix from your form values.
public ActionResult GetOnlyImportantPartOfModel([Bind(Prefix = "InnerModelToPost")] InnerModelToPost innermodel)
{
....
}
Having said that, if your only using properties of InnerModelToPost, then in your GET method, you can read the parent class (ComplexViewModel) from Session, but pass only the InnerModelToPost property to the view
I'm having trouble passing a viewmodel into a view. I have two views: a Search view and a GeneralForm view. Search passes search results into GeneralForm's viewmodel.
Say the GeneralForm is a complex viewmodel that holds two other viewmodels:
public class GeneralFormViewModel
{
public GeneralInfoViewModel GeneralInfo { get; set; }
public NotesViewModel Notes { get; set; }
}
public class GeneralInfoViewModel
{
[Required(ErrorMessage = "Please enter the person's name.")]
[DisplayName("Name:")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the person's ID.")]
[DisplayName("ID:")]
public int ID { get; set; }
}
public class NotesViewModel
{ // etc.
(I set up this way in order to use multiple #Html.BeginForms on my GeneralForm view. In this way, I hope to POST and validate small sections of the entire general form, one at a time, using KnockoutJS and AJAX.)
[HttpPost]
public ActionResult Search(SearchViewModel vm)
{
var query = // do some searching
var viewmodel = new GeneralFormViewModel()
{
GeneralInfo = new GeneralInformationViewModel
{
ID = query.id,
Name = query.name
}
};
return RedirectToAction("GeneralForm", viewmodel);
}
At this point, viewmodel.GeneralInfo is not null, and the viewmodel is passed to the GeneralForm controller.
[HttpGet]
public ActionResult GeneralForm(GeneralFormViewModel model)
{
return View(model);
}
Now model.GeneralInfo is null. What conventions of MVC am I breaking by doing this, and how can I get the GeneralForm view to render the data acquired via the Search controller to the GeneralForm view?
Problem is You can't send data with a RedirectAction.
you're doing a 301 redirection and that goes back to the client.
Store it in a TempData or Session ...
See the following post:
passing model and parameter with RedirectToAction
If I have the following model:
public class Model
{
public int ModelID { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
}
And the following controller method:
public ActionResult Create(Model model)
{
if (ModelState.IsValid)
{
model.Created = DateTime.Now;
// Save to DB
}
}
In the view the Created field is hidden as I want this to populate with the timestamp of when the Create controller method is called. This fails ModelState validation due to the model.Created property being null.
I don't want to make the model.Created property Nullable but I need to somehow specify that this field isn't required in the view. Can someone please advise how to accomplish this?
You'll want to exclude the Created property from binding using the [Bind] attribute, as follows:
public ActionResult Create([Bind(Exclude = "Created")] Model model)
{
....
}
It is also recommended for security reasons, as you don't want your client to set Created value for you.
I have model:
public class MyModel
...fields
[Remote(ActionName, ControllerName)]
public string SomeNumber { get; set; }
..fields
And have a action in ControllerName controller:
public JsonResult ActionName(string someNumber)
{...}
But when actions is invoked the parameter someNumber is allways null.
And when I try to debug it I get
GET /ControllerName/ActionName?MyModel.SomeNumber =34189736
How can I make it work?
(I can't pass whole model MyModel, and cant change MyModel.SomeNumber name of field in my view)
UPD. Input in my view:
<input data-val="true" data-val-remote-additionalfields="*.SomeNumber" data-val-remote-url="/ControllerName/ActionName" id="MyModel_SomeNumber" name="MyModel.SomeNumber" type="text" value="34189734" class="valid">
UPD solved! :)
I create new model with single field SomeNumber and use prefix:
SomeNumber([Bind(Prefix = "MyModel")]MySingleFieldModel model)
If you're using nested ViewModels, you'll need to accept the parent ViewModel as the argument in your Validation action. For example:
public class ParentViewModel
{
public UserViewModel User {get; set; }
//....
}
public class UserViewModel
{
[Remote("UniqueUsername", "Validation")]
public string Username { get; set; }
//....
}
In ValidationController:
public class ValidationController : Controller
{
public JsonResult UniqueUsername(ParentViewModel Registration)
{
var Username = Registration.User.Username; //access the child view model property like so
//Validate and return JsonResult
}
}
Try using you model as the parameter.
So that it could bind the value to it.
public JsonResult ActionName(MyModel model)
{
//...
model.SomeNumber;
//...
return Json(validationResult, JsonRequestBehavior.AllowGet)
}
public JsonResult ActionName(string SomeNumber)
{...}
I think you may need to match case on your input parameter.