After changing job I'm learning C# and Entity Framework; previously I worked with Java + Spring.
The question is: Is there an equivalent way to write this Java code into C# code?
public ModelAndView showUser(#RequestParam("k") String userName)
With Spring and the annotation RequestParam I could convert a request parameter named k into a more friendly and readable parameter named userName; so now, I expect a C# code like this:
public ActionResult showUser([RequestParam("k")] string userName)
Is this possible in some way?
I am not sure if you can do the same as in Java+spring but in C# MVC you can use Modal to transfer data from and to.
There you don't have to get the each and every request value separately you just have to mention your Modal Name in the parameter parentheses.
Answering your question, if tried to assign the value from the parameter it will throw
Default parameter for name must be a compile-time constant
public ActionResult Contact(string name = Request.Form["param1"])
{
return View();
}
Above code throws an error.
So to work with that used
public ActionResult Contact()
{
string name = Request.Form["param1"];
return View();
}
This will work.
I recommend you to use Modal and data annotations concept for the passing of data.
You can use that:
[HttpGet()]
public IActionResult showUser([FromQuery(Name = "k")] string userName)
{...}
Related
I like to use nameof() in my ASP.NET Core application when setting mvc errors using ModelState.AddModelError(). This reduces hidden errors since I pass the name of an attribute here. Compared to a string, this has the benefit that a compiler error is thrown when the attribute was renamed.
Example
class MyModel{
public string Name{get;set;}
}
public class MyController:Controller{
public IActionResult Test(MyModel model) {
// Will hiddenly fail when "Name" is renamed to something else
ModelState.AddModelError("Name", "The Name field is required!");
// Better: Using the auto renaming feature of VS, this will be updated if "Name" was renamed
ModelState.AddModelError(nameof(model.Name), "The Name field is required!");
}
}
This works, until I have another entity:
class MyModel{
public string Name{get;set;}
public MyOtherModel OtherModel{get;set;}
}
class MyOtherModel{
public string OtherName{get;set;}
}
Now I want to get the name of OtherModel. The problem: ASP.NET requires BaseClass.ChildClass pattern here, so OtherModel.OtherName in this example. Using the same logic like above:
public class MyController:Controller{
public IActionResult Test(MyModel model) {
ModelState.AddModelError(nameof(model.MyOtherModel.OtherName), "The Name field is required!");
}
}
will just give me the name of the child attribute, so OtherName in this example. But I need OtherModel.OtherName. Is there a clean way to get this without building the string itself?
This would be possible doing something like this:
string actionName = nameof(model.MyOtherModel) + "." + nameof(model.MyOtherModel.OtherName);
But not a very clean and intuitive way imho.
As others have suggested, you will probably have to write your own method to do this. This is what I came up with using Linq.Expressions:
string NameOfMember(Expression<Func<Model, object>> accessor)
{
string str = accessor.Body.ToString();
return str.Substring(str.IndexOf('.') + 1);
}
You would then use it like this: NameOfMember(model => model.MyOtherModel.OtherName)
I'm not familiar with ASP.NET but you can change Model to any type you want, including object.
As a side note, you shouldn't repeat "The Name field is required!" in your code. Maybe you can include that in your helper method as well.
what I try to do is to bind every incomming value from my response to a string or stringlist dynamicly / generic.
So assume I would know each POST-Value of my request, e.g.
string1 = Test
string2 = Test2
I would write:
[HttpPost]
public ActionResult DoFoo(string string1, string string2)
{
}
or
[HttpPost]
public ActionResult DoFoo(string string1, [Bind(Prefix = "string2")string myString2)
{
}
My situation know is, that I have X strings with my post request. So I dont know the exact number nor the names to catch in my backend.
How to catch every given Post-value without knowing this / how to catch the values dynamicly?
I don't feel that why you have to use Prefix with BIND, when you have to bind every incoming field of response. Bind is not a good choice for that. You can use bind if you have multiple entities at the same time. Reference here
that I have X strings with my post request.
If you have to use all the fields then you can use FormCollection or Model object to receive those fields. FormCollection automatically receive all the fields from view and bind them to a collection. See this for proper example. And a code snippet is below for reference.
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
Student student = new Student();
student.FirstName = collection["FirstName"];
student.LastName = collection["LastName"];
DateTime suppliedDate;
DateTime.TryParse(collection["DOB"], out suppliedDate);
student.DOB = suppliedDate;
student.FathersName = collection["FathersName"];
student.MothersName = collection["MothersName"];
studentsList.Add(student);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
However if you have to deal with only one particular field/set of fields then you can use either Include or Exclude as per your convenience with BIND. Example shown here and code snipped is added below.
In following way you are telling that you only want to include "FirstName" of User model while receiving the form content. Everything else will be discarded.
[HttpPost]
public ViewResult Edit([Bind(Include = "FirstName")] User user)
{
// ...
}
And in following example you are telling that, please exclude "IsAdmin" field while receiving the fields. In this case, value of IsAdmin will be NULL, irrespective of any data entered/modified by end-user in view. However, in this way, except IsAdmin, data rest of the fields will be available with user object.
[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
// ...
}
I am new to WebAPI and rest and am trying to do things correctly. By default if I were to access something such as User I would call api/user/5 if I wanted user 5. This would go to my User controller to Get(int num) I think. But I know I will often need other params passed as well. Currently I have Get(JObject data), but that data param is for other parameters. I will need other optional params whether I am sending an ID or wanting a list of everything. How do I go about organizing methods properly with WebAPI? Am I misunderstanding something?
To clarify:
This question is more about REST than dynamic objects, though they play a part:
How do I get a single resource vs a list of resources when I need additional params. I see those concepts as two separate methods, but the additional params complicate it in my mind when routing is involved.
Use attribute routing
For example -
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
or
[Route("customers/{customerId}/orders/{orderId}")]
public Order GetOrderByCustomer(int customerId, int orderId) { ... }
if you need to return a list, create a method that returns a list, otherwise return the specific item requested
Look into using JToken or the even more dynamic 'dynamic' (Taken from here)
"
JSON and JavaScript is really dynamic, though, and often it's a hassle to try to "deserialize" really dynamic JSON objects into strongly-typed .NET structures. JSON.NET and ASP.NET Web API's model binding offer a happy medium - a middle ground - called JToken.
public class ContactController : ApiController
{
public JToken Post(JToken contact)
{
return contact;
}
}
Using JToken gives a dynamic container but also a DOM-like navigation model. But if that's not dynamic enough for me, why can't my method's parameter just take a "dynamic."
C# is statically typed, sure, but that doesn't mean I can't statically type something dynamic. ;)
Again, note the watch window.
Using dynamic to catch JSON post payloads
public class ContactController : ApiController
{
public dynamic Post(dynamic contact)
{
return contact;
}
}
"
I think you should make a new object for each WebAPI function that will handle the request. You can make the parameters optional with nullable properties.
[HttpPost]
public void SampleFunction(SampleFunctionModel model)
{
}
where SampleFunctionModel is:
public class SampleFunctionModel
{
public int? Id { get; set; }
public string Name { get; set; }
}
Given the ASP.NET Web API route:
example/{Id}
Which maps to the following ApiController action method:
public void Example(Model m)
{
...
}
With the model class defined as:
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
When I post JSON { "Name": "Testing" } to the URL /example/123 then Id property of the Model object is not bound. It remains as 0 instead of 123.
How can I make the model binding also include values from the route data? I'd prefer not having to write custom model binders for what seems like a common use case. Any ideas would be greatly appreciated. Thanks!
The easiest way to accomplish what you're looking for is just to add another parameter to your method, and specify which parameter comes from which part of the request.
Example:
[HttpPost]
public void Example([FromUri]int id, [FromBody]Model m) {
// ...
}
Now your route of /examples/{id} will successfully be able to bind - because the Example method has a parameter called id which it is looking for in the URI. To populate your model, you can either pass the ID in there as well, or do something like the following:
[HttpPost]
public void Example([FromUri]int id, [FromBody]Model m) {
m.Id = id; // Make sure the model gets the ID as well.
}
Then simply post in { "Name": "Testing" } to /example/123 as you mentioned above.
Our built-in ModelBinding infrastructure doesn't support partial binding of object from both URI and body. You can, however, implement a custom IActionValueBinder to accomplish this task. For example, please refer to the blog post http://blogs.msdn.com/b/jmstall/archive/2012/04/18/mvc-style-parameter-binding-for-webapi.aspx.
The suggested process for this is normally to post to /example instead of /example/{id}. (though with Web API they normally use /api/{controller})
Check out the table half way down this page: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
Also check this link on "Inserting a record with ASP.NET Web API" - http://stephenwalther.com/archive/2012/03/05/introduction-to-the-asp-net-web-api.aspx
I don't think the default binder can associate your Id route value to your Model Id property, so whatever d1k_is answer is as good as it gets I'm afraid; either that or writing your own binder (you might be able to write a more generic binder maybe? -if you have like a DomainEntity super class or something like that...)
I have an MVC2 Application that uses MVVM pattern. I am trying use Data Annotations to validate form input.
In my ThingsController I have two methods:
[HttpGet]
public ActionResult Index()
{
return View();
}
public ActionResult Details(ThingsViewModel tvm)
{
if (!ModelState.IsValid) return View(tvm);
try
{
Query q = new Query(tvm.Query);
ThingRepository repository = new ThingRepository(q);
tvm.Things = repository.All();
return View(tvm);
}
catch (Exception)
{
return View();
}
}
My Details.aspx view is strongly typed to the ThingsViewModel:
<%# Page Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Config.Web.Models.ThingsViewModel>" %>
The ViewModel is a class consisting of a IList of returned Thing objects and the Query string (which is submitted on the form) and has the Required data annotation:
public class ThingsViewModel
{
public IList<Thing> Things{ get; set; }
[Required(ErrorMessage="You must enter a query")]
public string Query { get; set; }
}
When I run this, and click the submit button on the form without entering a value I get a YSOD with the following error:
The model item passed into the dictionary is of type
'Config.Web.Models.ThingsViewModel', but this dictionary
requires a model item of type
System.Collections.Generic.IEnumerable`1[Config.Domain.Entities.Thing]'.
How can I get Data Annotations to work with a ViewModel? I cannot see what I'm missing or where I'm going wrong - the VM was working just fine before I started mucking around with validation.
I don't think the problem is with the validation.
Change this line;
tvm.Things = repository.All(); //Is this the Linq extension method 'All()'?
to this
tvm.Things = repository.ToList();
I don't know what this is or what it does;
new ThingRepository(q);
It takes a string parameter and returns some kind of Linq IQueriable or List? If that's returning something else it could be causing the problem.
Do you have client-side validation enabled? It might even be a quick hacky-fix, but regarding the error message - it's tough to say without extra info. Could you post your View and the rendered Html?
What does your route for Details look like?
If you set a breakpoint at the start of the Details method, does it get hit when you click on the submit button?
It looks like you could just declare your ThingsViewModel like so:
public class ThingsViewModel: IEnumerable<Thing>
and then implement the interface as appropriate to access the Things list.
I think that ASP.NET MVC might be trying to map your view to the wrong controller. When you return the view you might need to specify the view file name you're trying to use.
return View("ViewName")