I'm doing a tutorial on MVC 3 and I stumbled upon the helper #Html.ActionLink(genre.Name, "Browse", new {genre = genre.Name}).
Now I understand what the values do and that the third value is a route parameter value but this is the first time I'm seeing this kind of syntax which is really bugging me for some reason.
What I mean exactly is new {genre = genre.Name}. I've come to understand that "new" precedes object/type declaration, however, this time it's simply the "new" keyword and the curly brackets. How exactly is this processed?
The syntax new { prop = val } creates an anonymous type. It's essentially the same as creating an instance of a class, except you're declaring the class and the instance all in one shot. Some people think that anonymous types are not statically typed or are not type safe. This isn't true. The types of the properties are inferred from the values they are assigned. This construction is used frequently in MVC and in linq.
Note that this syntax is not specific to MVC. You can use it anywhere it's convenient. I make a fair amount of use of anonymous types in day-to-day coding.
It's simple.. the first parameter is the link you want to display, so genre.Name can corresponds to Rock. The second argument is the action, the third argument your Controller class. The last parameter is the route values in the form of an anonymous object (an object you will never use again, the MVC engine uses the anonymous object in this case).
So your action(method) takes a string argument.
For example:
"Home" is the link the user sees (the first argument), Home (the second argument) is the action (method) to your Controller class, and it takes a string argument.
class HomeController
{
public ActionResult GenreAction(string genre)
{
}
}
When a request is made, it becomes Home/GenreAction/genre
It's a C# language feature called Anonymous Type, introduced with C# 3.5 if I'm not mistaken.
Related
I want to have a class that has a number of fields such as String, Boolean, etc and when the class is constructed I want to have a fieldname associated with each field and verify the field (using regex for strings). Ideally I would just like specify in the constructor that the parameter needs to meet certain criteria.
Some sample code of how :
case class Data(val name: String ..., val fileName: String ...) {
name.verify
// Access fieldName associated with the name parameter.
println(name.fieldName) // "Name"
println(fileName.fieldName) // "File Name"
}
val x = Data("testName", "testFile")
// Treat name as if it was just a string field in Data
x.name // Is of type string, does not expose fieldName, etc
Is there an elegant way to achieve this?
EDIT:
I don't think I have been able to get across clearly what I am after.
I have a class with a number of string parameters. Each of those parameters needs to validated in a specific way and I also want to have a string fieldName associated with each parameter. However, I want to still be able to treat the parameter as if it was just a normal string (see the example).
I could code the logic into Data and as an apply method of the Data companion object for each parameter, but I was hoping to have something more generic.
Putting logic (such as parameter validation) in constructors is dubious. Throwing exceptions from constructors is doubly so.
Usually this kind of creational pattern is best served with one or more factory methods or a builder of some sort.
For a basic factory, just define a companion with the factory methods you want. If you want the same short-hand construction notation (new-free) you can overload the predefined apply (though you may not replace the one whose signature matches the case class constructor exactly).
If you want to spare your client code the messiness of dealing with exceptions when validation fails, you can return Option[Data] or Either[ErrorIndication, Data] instead. Or you can go with ScalaZ's Validation, which I'm going to arbitrarily declare to be beyond the scope of this answer ('cause I'm not sufficiently familiar with it...)
However, you cannot have instances that differ in what properties they present. Not even subclasses can subtract from the public API. If you need to be able to do that, you'll need a more elaborate construct such as a trait for the common parts and separate case classes for the variants and / or extensions.
Error CA1822 : Microsoft.Performance : The 'this' parameter (or 'Me'
in Visual Basic) of 'SomeController.AnAction(string, string)' is never
used. Mark the member as static (or Shared in Visual Basic) or use
'this'/'Me' in the method body or at least one property accessor, if
appropriate.
A static action yields 404 not found when requested via URL. The action is working as expected with code analysis turned off. What's the point of this and what's the appropriate remedy?
Note that the return type of the action is PartialViewResult, it doesn't seem as though code analysis complains about this if the return type is ActionResult.
[HttpPost]
public PartialViewResult BlankEditorRow(string formId, Common.Entities.Common.ObjTypeEnum objType)
{
if (objType == Common.Entities.Common.ObjTypeEnum.Regular)
return new AjaxPartialViewResult("_RowEditor", new ProcedureEntryEntity()) { UpdateValidationForFormId = formId };
else
return new AjaxPartialViewResult("_TemplateRowEditor", new ProcedureEntryEntity()) { UpdateValidationForFormId = formId };
}
Update: Looks like changing the return type to ActionResult resolves the error, and PartialViewResult is an ActionResult so it should work.
I doubt that changing the return type without calling using any instance members really resolves the problem. I suspect that in order to change the return type, you changed the return statement to something which accessed an instance member.
Now I don't know whether the route handling in MVC will let you mark the method as static, but it's worth investigating. Even though the warning is given in terms of performance, I would think of it in terms of intent and readability.
Typically there are two reasons for a method or property to be an instance member (rather than static):
It needs to access another instance member, because the way it behaves depends on the state of the object
It needs to behave polymorphically based on the actual type of the instance it's called on, so that the behaviour can be overridden
If neither of these is the case, then the method can be made static which indicates that there's no polymorphism expected and no instance state required. A static member effectively advertises that the only state it depends upon is the state of the type itself (and the parameters), and that it won't behave polymorphically. Aside from anything else, that means you can test it without creating an instance at all, too.
Of course, if MVC's infrastructure requires it to be an instance method, then you should just suppress the warning, with a comment to indicate that fact.
I think CA just does not take into account that this is a controller action in MVC app. I would suppress.
How do you get the object parameters, which action method was called with at run-time, to accomplish something to the effect of the following
public ActionResult Index(Int32? x, Int32? y, DateTime? z, NumberStyles n) {
this.RouteData.Values["x"] = x
this.RouteData.Values["y"] = y
this.RouteData.Values["z"] = z
this.RouteData.Values["n"] = n
return View();
}
It seems like it should be a possible to the names and values of each parameter without this kind of tedious code.
Sometimes you can get the parameters which the action method was called with, by looking in RouteData, but this isn't always the case, particularly if the action method was invoked with an ajax request, the parameters may not show up in the RouteData, and instead show up in the Request Params.
What I'm looking for, is a generic way to get each parameter that is defined in the action method signature at run-time, and gets the parameter's actual object, run-time value, not just a string. Further more, it should work no matter how the action method was invoked, whether it may be the result of ChildActionExtensions.Action or an ajax callback.
RouteData and Request Params don't seem to have what I'm looking for.
Your code sample is setting values back into the RouteData collection. Are you trying to pass parameters to your view using the RouteData collection? That's not what it exists for, you might consider using ViewBag instead.
Or, create a POCO which contains all your properties and let the data binder do all the work (so use #model YourType in your view and pass a single argument to your view. The default model binder will map the individual argument values for you).
As far as the input value collections are concerned, there's a good reason why the value is not to be found consistently in the collections you've mentioned.
Perhaps the trick here is to clarify what's going on prior to your action being invoked. The arguments to your action method can come from more than one source. For example, it may come from:
The URL Path
The URL query string (eg: in a GET, the parameters after the question mark ?)
POSTed form data
Explicit arguments from another action
In your code sample above, the RouteData collection will only contain the value of "x" if your route has a matching parameter name.
For example: "{controller}/{action}/{x}". (this is a custom route pulling "x" from the path)
Failing that, the values will be resolved using the default model binder and will be pulled from either the query string parameters or POST data as the case may be.
The route value will take precedence. So if the above custom route was applied, the following URL:
http://www.example.com/Something/Index/1?x=2
would invoke your action with x=1. The 1 would then be found in the RouteData as pulled from the URL path and the x=2 found in the Request.QueryString would be ignored.
If you are concerned with how x got its value, then you must take into account all of the above so you know where to look. There is also the question of which route is applied to the request, but that's another topic altogether.
All the input came across the wire as text.. it was the model binder that examined your action signature and converted to the types you specified (wherever that is possible).
So, I don't think what you are asking for exists even conceptually in this setting.
the signature for this very useful method states I can indicate a type:
public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)
... the docs very understandably state that TModel is "The type of model". It must be my particular bent that this description conveys no meaning to me whatsoever. I've googled for an explanation but found zilch.
I'm in a view where #model Website.Models.Product but want to create an editor for something of a different type. I thought I could:
#Html.EditorFor(#ViewBag.AClassOfTheOtherType)
or maybe (I'm obviously guessing):
#Html.EditorFor(TheOtherType)
but that is not acceptable syntax and so I thought:
#Html.EditorFor(x => x...)
but the lambda expression seems to be bound to #model... so I thought, "ah!":
#Html.EditoFor<TheOtherType>(...)
but VS thinks the < starts an HTML tag and indicates the end of my EditorFor call (which fails).
aaaaahhhhh!
how do I do this (in case I actually need to ask)?
Haven't tested this, but couldn't you do:
#Html.EditorFor(x => ViewBag.AClassOfTheOtherType)
You don't necessarily need to use the variable passed into the Lambda.
Model - is the Model - the M in MVC
TModel could just as well be sdserweJJG - it's only consistently called TModel out of convention.
Within the helper method for EditorFor you will see something like:
TValue val = expression.Compile()(htmlHelper.ViewData.Model);
this is where the extension method compiles the lambda passed in - for example the x=>x.Model.Property part - and gets back the actual Model data to use to build the actual display controls.
The Model is passed to the view when you call return View(viewModel); from your controller action.
What you are trying to do doesn't make sense because the method was designed to work with the views Model.
You can however use #Html.Editor as this will take the actual value in the way you are trying:
#Html.Editor(ViewBag.AClassOfTheOtherType)
The sourcecode for MVC is freely available to download and view - it's well worth taking the time to do so :)
the answer is (drumroll please)... yes, one can bind the lambda expression with the type declarator. the only problem is the Visual Studio editor, which thinks one is ending the C# part and entering the HTML part with the opening < and thus disallows proper code. Solution:
#{ Html.EditoFor<TheOtherType>(...) }
Important The question is not "What does Queryable.OfType do, it's "how does the code I see there accomplish that?"
Reflecting on Queryable.OfType, I see (after some cleanup):
public static IQueryable<TResult> OfType<TResult>(this IQueryable source)
{
return (IQueryable<TResult>)source.Provider.CreateQuery(
Expression.Call(
null,
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(
new Type[] { typeof(TResult) }) ,
new Expression[] { source.Expression }));
}
So let me see if I've got this straight:
Use reflection to grab a reference to the current method (OfType).
Make a new method, which is exactly the same, by using MakeGenericMethod to change the type parameter of the current method to, er, exactly the same thing.
The argument to that new method will be not source but source.Expression. Which isn't an IQueryable, but we'll be passing the whole thing to Expression.Call, so that's OK.
Call Expression.Call, passing null as method (weird?) instance and the cloned method as its arguments.
Pass that result to CreateQuery and cast the result, which seems like the sanest part of the whole thing.
Now the effect of this method is to return an expression which tells the provider to omit returning any values where the type is not equal to TResult or one of its subtypes. But I can't see how the steps above actually accomplish this. It seems to be creating an expression representing a method which returns IQueryable<TResult>, and making the body of that method simply the entire source expression, without ever looking at the type. Is it simply expected that an IQueryable provider will just silently not return any records not of the selected type?
So are the steps above incorrect in some way, or am I just not seeing how they result in the behavior observed at runtime?
It's not passing in null as the method - it's passing it in as the "target expression", i.e. what it's calling the method on. This is null because OfType is a static method, so it doesn't need a target.
The point of calling MakeGenericMethod is that GetCurrentMethod() returns the open version, i.e. OfType<> instead of OfType<YourType>.
Queryable.OfType itself isn't meant to contain any of the logic for omitting returning any values. That's up to the LINQ provider. The point of Queryable.OfType is to build up the expression tree to include the call to OfType, so that when the LINQ provider eventually has to convert it into its native format (e.g. SQL) it knows that OfType was called.
This is how Queryable works in general - basically it lets the provider see the whole query expression as an expression tree. That's all it's meant to do - when the provider is asked to translate this into real code, that's where the magic happens.
Queryable couldn't possibly do the work itself - it has no idea what sort of data store the provider represents. How could it come up with the semantics of OfType without knowing whether the data store was SQL, LDAP or something else? I agree it takes a while to get your head round though :)