I'm using remote validation with complex type. As the name of my field can be something like name="user.name", I need to use the BindAttribute like that
public JsonResult ValidName[Bind(Prefix="user.name")]string name){ ... }
or the binding will not work.
The problem is that there will be many different name that end with "user.name" like "employee.user.name" or "manager.user.name".
So, is it possible to bind all field where the name end with "user.name" to string name in the method declaration?
You are misunderstanding the use of Prefix. Its for identifying what a complex property name (dot notation) starts with, not ends with. If for example you had a view model MyModel with a complex property Organisation with a complex property Address with a property City then in you view, you might have
#model MyModel
#Html.TextBoxFor(m => m.Organisation.Address.City)
would render the following html
<input name="Organisation.Address.City" ...... />
If you only wanted to post back the value of City then you would use
public ActionResult Edit([Bind(Prefix="Organisation.Address")] string city)
Similarly if you only wanted to post back all values of Address, it would be
public ActionResult Edit([Bind(Prefix="Organisation")] Address address)
{
string city = address.City;
So in your case above, you would need both
public JsonResult ValidName[Bind(Prefix="employee.user")] string name)
and
public JsonResult ValidName[Bind(Prefix="manager.user")] string name)
You can use Request.QueryString to manually bind the parameter that you want in the controller method. Here is a quick code to bind the first parameter that end with the specified suffix
private bool EndWith(string input, string end)
{
string pattern = #"" + end + #"$";
Regex rx = new Regex(pattern, RegexOptions.IgnoreCase);
return rx.Match(input).Success;
}
private string bindSuffix(string suffix)
{
string result = null;
foreach (var key in Request.QueryString.AllKeys)
{
if (EndWith(key, suffix))
{
result = Request.QueryString[key];
}
}
return result;
}
//Then use it like that
public JsonResult ValidName()
{
string name = bindSuffix("user.name");
...
}
Related
I know this seems pretty basic, and it should be, but I can't find out where I am going wrong. (I hve read other articles with similar titles on SO, and other resources on the web but still cant figure it out).
I have a controller and in it I am setting a string variable. Now I don't mind if this takes the form of a property, an ActionResult, or a straight method. I just want a simple string that I can play with in the controller, and return it to the view.
Essentially what I am trying to do is list the files in a given folder. So my logic is like this:
Find the current folder (partially successful)
Append the path to the where the files you want to located are. i.e. if my current folder is Web\ then I will append something like "Content\CSS" if I wanted to list all the CSS files for example. (I do this because I want to allow the user to dynamically change the site by selecting the css to apply). So it would look like:
CurrentPath += "Content\CSS"
I want load the file names into an array or list
I want to pass this list to my view to render in a combo box (which is on my _Layout.cshtml).
It is important to know that I am trying to view the string on the _Layout.cshtml as I cant just build another view for it. (Unless I am wrong, in that case I would appreicate any help).
At the moment I am still working on getting a simple string passed to my view in a way I can freely manipulate it like in step 2.
I started off with a separate static class and a global variable:
public static class MyTheme
{
public static string CurrentPath = HostingEnvironment.MapPath("~");
}
In my view I had:
#Html.Label(MyProject.Web.Controllers.MyTheme.CurrentPath);
This worked but when I tried to use an if statement to determine if the string was null or empty I got errors. So my next attempts all failed.
Next I decided to bring it into a controller (in this case my BaseController) and this is when I started running into problems. Code below:
Inside BaseController Class
public ActionResult ThemePath()
{
string currentPath = Server.MapPath("~");
if (string.IsNullOrEmpty(currentPath))
{
currentPath = "Error!";
}
else
{
currentPath = "Our Path Is: " + currentPath;
}
return View(currentPath);
}
I dont know how to access and run this from inside my _Layout.cshtml view
So next I tried a standard method inside BaseController:
public string ThemePath()
{
string currentPath = Server.MapPath("~");
if (string.IsNullOrEmpty(currentPath))
{
currentPath = "Error!";
}
else
{
currentPath = "Our Path Is: " + currentPath;
}
return currentPath;
}
Again I don't know how to access it in the view
Finally I tried to use ViewBag and ViewData and now I am just going bonkers! So in my base controller I have:
public string ThemePath()
{
ViewBag.currentPath = Server.MapPath("~");
if (string.IsNullOrEmpty(ViewBag.currentPath))
{
ViewBag.currentPath = "Error!";
}
else
{
ViewBag.currentPath = "Our Path Is: " + ViewBag.currentPath;
}
return ViewBag.currentPath;
}
and in my view I have
#Html.Label(ViewBag.CurrentPath);
or even
#Html.Label(ViewBag.CurrentPath.ToString());
With the following friendly little error messages:
CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'Label' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
Finally I tried ViewData in the base as follows:
public string ThemePath()
{
ViewData["currentPath"] = Server.MapPath("~");
if (string.IsNullOrEmpty(ViewData["currentPath)"].ToString()))
{
ViewData["currentPath"] = "Error!";
}
else
{
ViewData["currentPath"] = "Our Path Is: " + ViewData["currentPath"];
}
return ViewData["currentPath"].ToString();
}
and correspondingly in the _Layout.cshtml I tried:
#Html.Label(ViewData["CurrentPath"].ToString());
Without the .ToString() I get the above error:
With the .ToString() I get a null refrence execption error.
Where am I going wrong?
To pass a string to the view as the Model, you can do:
public ActionResult Index()
{
string myString = "This is my string";
return View((object)myString);
}
You must cast it to an object so that MVC doesn't try to load the string as the view name, but instead pass it as the model. You could also write:
return View("Index", myString);
.. which is a bit more verbose.
Then in your view, just type it as a string:
#model string
<p>Value: #Model</p>
Then you can manipulate Model how you want.
For accessing it from a Layout page, it might be better to create an HtmlExtension for this:
public static string GetThemePath(this HtmlHelper helper)
{
return "/path-to-theme";
}
Then inside your layout page:
<p>Value: #Html.GetThemePath()</p>
Hopefully you can apply this to your own scenario.
Edit: explicit HtmlHelper code:
namespace <root app namespace>
{
public static class Helpers
{
public static string GetThemePath(this HtmlHelper helper)
{
return System.Web.Hosting.HostingEnvironment.MapPath("~") + "/path-to-theme";
}
}
}
Then in your view:
#{
var path = Html.GetThemePath();
// .. do stuff
}
Or:
<p>Path: #Html.GetThemePath()</p>
Edit 2:
As discussed, the Helper will work if you add a #using statement to the top of your view, with the namespace pointing to the one that your helper is in.
Use ViewBag
ViewBag.MyString = "some string";
return View();
In your View
<h1>#ViewBag.MyString</h1>
I know this does not answer your question (it has already been answered), but the title of your question is very vast and can bring any person on this page who is searching for a query for passing a simple string to View from Controller.
Why not create a viewmodel with a simple string parameter and then pass that to the view? It has the benefit of being extensible (i.e. you can then add any other things you may want to set in your controller) and it's fairly simple.
public class MyViewModel
{
public string YourString { get; set; }
}
In the view
#model MyViewModel
#Html.Label(model => model.YourString)
In the controller
public ActionResult Index()
{
myViewModel = new MyViewModel();
myViewModel.YourString = "However you are setting this."
return View(myViewModel)
}
#Steve Hobbs' answer is probably the best, but some of your other solutions could have worked. For example,
#Html.Label(ViewBag.CurrentPath); will probably work with an explicit cast, like #Html.Label((string)ViewBag.CurrentPath);. Also, your reference to currentPath in #Html.Label(ViewData["CurrentPath"].ToString()); is capitalized, wherein your other code it is not, which is probably why you were getting null reference exceptions.
Just define your action method like this
public string ThemePath()
and simply return the string itself.
If you are trying to simply return a string to a View, try this:
public string Test()
{
return "test";
}
This will return a view with the word test in it. You can insert some html in the string.
You can also try this:
public ActionResult Index()
{
return Content("<html><b>test</b></html>");
}
I'm trying to bind a single parameter of a URL query to a single property in an action method.
The URL is along the lines of:
/user/validate?Some.Prefix.Username=MyUserName
And my controller and action method are along the lines of:
public class UserController : Controller
{
public IActionResult Validate([Bind(Prefix = "Some.Prefix")]string username)
{
return Ok(username);
}
}
However the username parameter is always null when this action method is called. It seems this is a result of using the BindAttribute with a string parameter, rather than a simple class parameter. If I replace the string username parameter with a simple class containing a Username property, I can capture the value as expected.
public class UserController : Controller
{
public IActionResult Validate([Bind(Prefix = "Some.Prefix")]ValidationModel model)
{
return Ok(model);
}
}
public class ValidationModel
{
public string Username { get; set; }
}
Is there any way to bind to a single parameter (rather than a class parameter) when the URL parameter name contains prefixes?
For simple types like int and string, the Bind Prefix overrides the model name for the parameters. Using your action method as an example, the DefaultModelBinder would be looking for the name "Some.Prefix" instead of "username".
So, if you want to work around this and not require a complex type, you need to specify the fully qualified name.
public IActionResult Validate([Bind(Prefix = "Some.Prefix.Username")]string username)
public Class SomeModel
{
public int Id { get; set;}
public string Name {get; set;}
}
this is the method I'm binding values to above model, it contains inline SQL Queries
Public ActionResult GetData()
{
IEnumarable<SomeModel> alltheListValues = ....
}
using above method, I want to filter all the record that containing ids in following string.
string filterIds = "12,13,14,15"
SomeModel model class Id values are in Integer type, but I have string type id set, without going for looping this, I decided to use WHERE IN query to filter this.
since WHERE IN query we can get in Linq as contains
I wrote down follwoing function to filter values
IEnumarable<SomeModel> filterValues = GetData.Where(Id=> Id.ToString().Contains(filterIds));
but this is not selecting any value always zero filter result, how can I wrote this properly
This could be a way to go:
string filterIds = "12,13,14,15";
//Convert filterIds string into a integers collection
var ids=filterIds.Split(',').Select(int.Parse);
IEnumarable<SomeModel> filterValues = GetData().Where(sm=> ids.Contains(sm.Id));
One thing I noticed now is the signature of your GetData method, I think what you mean is:
public IEnumarable<SomeModel> GetData()
{
IEnumarable<SomeModel> alltheListValues = ....
//...
return alltheListValues;
}
Have a array/collection instead of a list and check if the id is in it.
IEnumarable<SomeModel> filterValues = ActualGetData().Where(n => filterIds.Contains(n.Id))
Where ActualGetData() returns you an IEnumarable.
In your current code GetData() returns an ActionResult as Drew Kennedy mentioned
If you are sure that all the elements of collection of "Id" will be convertible to number then you can use following approach.
var models = new List<SomeModel>(); //Consider that this collection is coming from some service or repository.
var Ids = filterIds.Split(',').Select(x => int.Parse(x));
IEnumarable<SomeModel> filterValues = models.Where(n => Ids.Contains(n.Id));
Your code wound't compile so I am posting here just the logical code here. You can use it as per your requirement.
I'd like to bind to a dynamic object from the request querystring in ASP.NET Web API. Whilst decorating the action parameter with [FromUri] works with a normal class, it does not appear to work with dynamic (the dynamic object is empty).
public dynamic Get(string id, [FromUri]dynamic criteria)
{
return Ok();
}
Note that this needs to work for GET requests so there is no body.
You might be interested in the GetQueryNameValuePairs extension method (docs).
While it doesn't bind the query parameters to a model, it does allow you to access query parameters in a dynamic way (which sounds like your ultimate goal) via a dictionary-like object.
Also, see this answer.
var dict = new Dictionary<string, string>();
var qnvp = this.Request.GetQueryNameValuePairs();
foreach (var pair in qnvp)
{
if (dict.ContainsKey(pair.Key) == false)
{
dict[pair.Key] = pair.Value;
}
}
No it can't work.
The [FormUri] attribute tries to bind the object properties to the query string properties by name.
A dynamic object has no properties so it can't bind.
You can create your own model binder to achieve this goal. I don't suggest for you to go that way, but it is possible.
The "problem" with dynamics in this case is that it is not compiler safe and you can get errors at runtime if the parameters you expect are not part of the request.
While Web API complains that Multiple actions were found that match the request when overriding the Get method with a single parameter, you can "trick" the default model binder into binding the model you want by adding another parameter.
public class House
{
public string Color { get; set; }
public double SquareFeet { get; set; }
public override string ToString()
{
return "Color: " + Color + ", Sq. Ft.:" + SquareFeet;
}
}
public class Car
{
public string Color { get; set; }
public double EngineSize { get; set; }
public override string ToString()
{
return "Color: " + Color + ", cc: " + EngineSize;
}
}
public class ValuesController : ApiController
{
public string Get([FromUri] bool house, [FromUri] House model)
{
return model.ToString();
}
public string Get([FromUri] bool car, [FromUri] Car model)
{
return model.ToString();
}
}
Using the above code, the following URLs produce the respective output:
~/api/values?house=true&color=white&squarefeet=1500
<string>Color: white, Sq. Ft.:1500</string>
~/api/values?car=true&color=black&enginesize=2500
<string>Color: black, cc: 2500</string>
I'm trying to extract the parameters of my URL, something like this.
/Administration/Customer/Edit/1
extract: 1
/Administration/Product/Edit/18?allowed=true
extract: 18?allowed=true
/Administration/Product/Create?allowed=true
extract: ?allowed=true
Someone can help? Thanks!
Update
RouteData.Values["id"] + Request.Url.Query
Will match all your examples
It is not entirely clear what you are trying to achieve. MVC passes URL parameters for you through model binding.
public class CustomerController : Controller {
public ActionResult Edit(int id) {
int customerId = id //the id in the URL
return View();
}
}
public class ProductController : Controller {
public ActionResult Edit(int id, bool allowed) {
int productId = id; // the id in the URL
bool isAllowed = allowed // the ?allowed=true in the URL
return View();
}
}
Adding a route mapping to your global.asax.cs file before the default will handle the /administration/ part. Or you might want to look into MVC Areas.
routes.MapRoute(
"Admin", // Route name
"Administration/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
If it's the raw URL data you are after then you can use one of the various URL and Request properties available in your controller action
string url = Request.RawUrl;
string query= Request.Url.Query;
string isAllowed= Request.QueryString["allowed"];
It sounds like Request.Url.PathAndQuery could be what you want.
If you want access to the raw posted data you can use
string isAllowed = Request.Params["allowed"];
string id = RouteData.Values["id"];
public ActionResult Index(int id,string value)
This function get values form URL
After that you can use below function
Request.RawUrl - Return complete URL of Current page
RouteData.Values - Return Collection of Values of URL
Request.Params - Return Name Value Collections
You can get these parameter list in ControllerContext.RoutValues object as key-value pair.
You can store it in some variable and you make use of that variable in your logic.
I wrote this method:
private string GetUrlParameter(HttpRequestBase request, string parName)
{
string result = string.Empty;
var urlParameters = HttpUtility.ParseQueryString(request.Url.Query);
if (urlParameters.AllKeys.Contains(parName))
{
result = urlParameters.Get(parName);
}
return result;
}
And I call it like this:
string fooBar = GetUrlParameter(Request, "FooBar");
if (!string.IsNullOrEmpty(fooBar))
{
}
In order to get the values of your parameters, you can use RouteData.
More context would be nice. Why do you need to "extract" them in the first place? You should have an Action like:
public ActionResult Edit(int id, bool allowed) {}
I'm not familiar with ASP.NET but I guess you could use a split function to split it in an array using the / as delimiter, then grab the last element in the array (usually the array length -1) to get the extract you want.
Ok this does not seem to work for all the examples.
What about a regex?
.*(/|[a-zA-Z]+\?)(.*)
then get that last subexpression (.*), I believe it's $+ in .Net, I'm not sure