Strongly-typed T4MVC Action/ActionLink - c#

I've been using T4MVC (FYI: v2.6.62) for quite some time, and I've been slowly moving over our code to this way of working (less reliance on magic strings).
But I've had to stop because, for some reason, T4MVC is unable to translate objects into urls, and only seems to be able to work on primitive types (int/string/etc).
Here is an example:
Route breakdown:
/MyController/MyAction/{Number}/{SomeText}
Class:
namespace MyNamespace
{
public class MyClass
{
public int Number { get; set; }
public string SomeText { get; set; }
}
}
Controller:
public class MyController
{
public virtual ActionResult MyAction(MyClass myClass)
{
return View();
}
}
View:
<%= Html.Action(
T4MVC.MyController.Actions.MyAction(
new MyClass()
{
Number = 1,
SomeText = "ABC"
}
) %>
The end result is this:
/MyController/MyAction?myClass=MyNamespace.MyClass
and not
/MyController/MyAction/1/ABC
Does anyone else have this problem? Are T4MVC urls like this available?
Question also asked at the ASP.NET Forum.

Update (10/11/2012): the recently added support for Model Unbinders (see section 3.1 in the doc) should hopefully cover a lot of these cases.
Original answer:
Copying my reply from the forum thread:
Hmmm, I don't think this has come up yet. Maybe in most cases that people have Action methods that take an object, the object's values come from posted form data, rather than being passed on the URL? In such scenario, the question doesn't arise.
I think in theory T4MVC could be changed to support this. It would just need to promote all the object's top level properties as route values rather than try to use the object itself (obviously, the current behavior is bogus, and is a result of just calling ToString() blindly).
Have others run into this and think it's worth addressing?

If I've understood the problem correctly then the following syntax should allow you to work around the problem.
<%= Html.ActionLink("test", MVC.MyController.MyAction().AddRouteValues(new MyClass() { Number = 5, SomeText = "Hello" })) %>
I think the answer to make the syntax nicer would be to wrap each non value type parameter in a RouteValueDictionary in each generated action result method
Edit: (Response to comment as not enough chars)
Ah ok I managed to recreate the simple example above using this method to give: /MyController/MyAction/5/Hello as the url.
I'm not quite sure how nested complex types would pan out in practice. You could use some recursion to dive down the into the top-level object and reflect over the values to add them but then you open up a new set of issues, such as how to cope with a child property name that is identical to the parent property name.
This seems like it could be a complex problem to solve, in a manner that would work for everyone.
Perhaps some kind of adapter pattern would be most useful to transform a complex object into route values. In the simplest case this might be to declare an extension method ToRouteDictionary that acts on your complex type and transforms it using your knowledge of how it should work. Just thinking out loud as I'm obviously not aware of your use cases

Related

.Net Core Binding to a Specific Model given a Specific QueryString Value

I'm in the middle of refactoring an analytics api which needs to allow clients to send events as HTTP GET requests, with their "Hit" data encoded in the URL's QueryString Parameters.
My API's job is to recieve these events, and then place the "valid" events onto a queue in another part of the system for processing.
Some Hits have the same shape. The only thing that makes them different is the value of the type parameter, which all events must have at a minimum.
The problem I've encountered is that based on the Hit type, I'd like to be able to assume the type of each field given to me, which requires model binding. Of course. Currently, I can only find out what model to validate against after checking the value of type - which risks making the API excessively "stringly typed"
An example route would be:
GET https://my.anonymousanalytics.net/capture?type=startAction&amount=300&so_rep=true
Therefore, my Hit would be:
{
type: "startAction",
amount: 300,
so_rep: true
}
Which, hypothetically, could be bound to the Model StackOverflowStartHitModel
class StackOverflowStartHitModel {
public string type { get; } // Q: Could I force the value of this to be "startAction"?
? public int amount { get; }
public boolean so_rep { get; }
}
Why am I asking this here? Well I'm normally a JavaScript developer, but everyone who I'd normally turn to for C# wisdom is off work with the flu.
I have experimented with the [FromQuery] attribute decorator, but my concern is that for Hits that are the exact same shape, I might not be able to tell the difference between whether it is a startAction or an endAction, for example.
you're going to need to have a validation engine of some sort, but do not confuse this with your UI model validation. It sounds like you really have one model with a number of valid states which really is business logic.
Your model looks like this:
public class StackOverflowModel
{
public string type { get; set;}
public int amount { get; set; }
public bool so_rep { get; set;}
}
it doesn't matter what value your type field has and you don't need to hard-code it either, it will be captured as is and then it can be checked against valid states.
There are a number of ways to do this, that I can think of.
One option would be to create a list of valid rules ( states ) and then simply check if your input model matches any of them. One way to implement something like this could be with a library like FluentValidation. You can see an example here: Validation Rules and Business Rules in MVC
Another option would be to use some sort of Pattern Matching techniques like described here: https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching
Whichever option you go with, make sure you put this validation stuff in a separate class, maybe even a separate project. You can then add tests for each rule that you have to make sure everything works. This will also keep your controller light.
You haven't given examples of valid and invalid states, but I am guessing you're really talking about variations of those 3 parameters such as, when type is "something" then amount can only be < 200 and so_rep can only be "whatever". This can be done quite nicely with the FluentValidation library.

API Versioning - What do I do if model changes

I'm fairly new with APIs and versioning but from what I understand, the developer (which is me) should retain the code if there will be a contract breaking change for the API. Correct me if I'm wrong but I consider Model changes as contract breaking change.
So my question is - Do you make a new model (ex. ModelName.V2) just for the sake of versioning? Is there a better way to do this? This would mean even a slight change in property in my model would mean I would iterate it to another version.
p.s. let me know if I need to edit my question as I'm also fairly new in StackOverflow.
Sample
public class Product
{
public int ID {get;set;}
public string Name {get;set;}
}
and accompanying Controller
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public class Products : Controller
{
Product[] prod = new Product[]{
new Product(){ID = 1, Name = "T-Shirt"},
new Product(){ID = 2, Name = "Jeans"}
};
[HttpGet]
[ActionName("gotcha")]
public IActionResult GetProduct()
{
return Ok(prod);
}
}
and for V2 Controller
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public class V2.Products : Controller
{
[HttpGet]
[ActionName("gotcha")]
public IActionResult GetProduct()
{
var trash = "Hello World!";
return OK(trash);
}
}
The above codes are what I understand as contract breaking and needed versioning and below is my problem with Model contract breakage:
public class Product
{
public int ID {get;set;}
public string Name {get;set;}
public decimal Price {get;set;}
}
So the sample above shows I added a new property. This I consider as contract breakage and do I iterate a new controller version and then retain the old Model as well? In the future this will be messy if I keep legacy versions.
First, you only need to reversion if there's a breaking change. Not everything is necessarily a breaking change, and typically adding a new property is not in fact a breaking change. Outdated clients should simply ignore it, and if not, that's more on the client than you, as they'd be doing something weird/wrong to cause anything to break that way. You need to be more concerned about changes or deletions, which from a client perspective are kind of the same thing; with a change, it's as if the old property was removed and new one was added. Even then, though, it only matters if the name or the type changes. Any under the hood processing doesn't matter, and technically, even if you change the property name, you can utilize something like the JsonProperty attribute to make the serialization return the old name, if you want.
Assuming you do have a breaking change, then yes, you should create a new version of your model class, and probably a new action/controller to go with it, both named with the new version number, i.e. Product2 and GetProduct2 and/or Product2Controller, etc. Yes, this can lead to code duplication, but there's two things you can do to minimize that:
Use inheritance if possible. For example, Product2 can inherit from Product and simply override whatever property needs to change. If you just add a new GetProduct2 action, you can factor out the original code for GetProduct into a private generic method GetProduct2<TProduct>, and then reimplement the original (and new) method to simply return that, i.e. return GetProduct<Product>(); and returnGetProduct();`. These are just examples. There's many different ways to handle this, but the point is that it doesn't necessarily require major code duplication to do versioning.
If you notice your codebase is starting to feel cluttered, you can begin deprecating API versions. Issue a notice to your clients that one or more of your oldest versions are now deprecated. Then, after a reasonable amount of time (depending on the complexity of the changes required to get up to date), remove that old code in a new release. This will of course break any outdated clients, but they were forewarned and given time to change, so if they don't that's on them. You'll notice all the big boys do this from time to time. I know I've been receiving a ton of emails from Facebook warning of pending API version removals. That's essentially what they're doing behind the scenes: cleaning their codebase.
When I do a API versioning. I add a new model with the Version number just to be able to track down the changes in data data structure, example:
public class ProductV2
{
//New attributes
}
I would just inherit attributes from the previous version, if the new model is similar to the old one plus new attributes:
public class ProductV2 : Product
{
//New attributes
}
Hopefully I understood your question this time.

How to load an Entity Framework data object without explicitly setting each property

I want to be able to do something like the following:
var book = new Book();
book.LoadByPrimaryKey(id); //returns bool
The issue I am coming across is I can't figure out if there is a simple way to load data into an object generated using Entity Framework. I understand how to grab the information needed to fill the object, but is there a simple way to fill out all the properties of an object without explicitly going through each property and setting it to the desired value? In C# I cannot simply type:
this = db.Books.Single(d => d.BookId == id);
I instead have to explicitly set each property:
var book = db.Books.Single(d => d.BookId == id);
this.Title = book.Title;
this.PageCount = book.PageCount;
...
Is there a way around doing this when wanting to load up an object? Maybe something with a DbDataReader? I have used the data reader to load DataTables, but can't figure out how to use them to populate an object. Maybe I'm over thinking it.
When you need to copy all of the properties from one object to another you can
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
As David Browne previously answered:
Just write the code (typing practice)
Generate the code using a T4 Template
Use Reflection
Use Automapper
The answer he gave you is correct. But I'm want to extend it and explain why.
First, let put some concept here. When we go further in programming techniques, sometimes, the working answer, it not enough. Although what you trying to do is a valid solution for the problem, there is some issue with it.
The is a concept that is called S.O.L.I.D. The first letter (S) stands for Single Responsibility Principle. This means that one object should have only one responsibility.
The problem in your approach is you are putting multiple responsibilities in a single object:
Hold/Transport information about a book.
Load from a remote server (in this case a DataBase) information about a book.
You probably googled this issue before post here, and I suspect you found nothing useful. Now the reason you found nothing is because this is a bad approach, it goes against the SOLID concepts, and it breaks several interation with possible Design Patterns. So this is why you probably found nothing, there is no previous conceived tool of workaround to this problem, because this is a discouraged approach, so no one, with a little understand of program techniques, will help you.
Therefore, we go back to the answer that David Browne gave you. To use Automapper (the simplest of the suggestions). You need to change your approach. Consider to separate each responsibility in a different class:
class BookDA // DAO = data access
{
private MyDbConnection db;
public BookTO Get()
{
var book = db.Books.Single(d => d.BookId == id);
return book;
}
}
class BookTO // TO = transport object
{
public string Name { get; set; }
}
In the code above each responsibility is associated with a different class. This answer became too long but I hope it helps.

Deny HTML in WebAPI model properties

I've been searching for this for a while, and couldn't find anything, apologies if there is something and I've missed it.
Is there anything in the Web-API 2 framework that will automatically reject HTML tags on string model properties (except for a select few)?
I know I could create a custom validation attribute, and whack it on every property, but that's a lot of over head to maintain and remember to do on all new models.
public class Person {
public string Name{ get; set; }
// ... snipped
}
I can make a post request to my POST endpoint with JSON similar to:
{
"name": "<h1>This is my name</h1>"
}
In the action the person.Name will be equal to "<h1>This is my name</h1>", with no validation errors raised
I was looking for the same thing as you. Coming from a MVC standpoint where we have parameters to disallow html in input fields in forms, this seems reasonable.
I found this library tho, that sort of, in a way might help out... It does not fully answer your question in the way you want it, but it helps out with the custom attributes you would otherwise have to generate by yourself, if you decided to go for an attribute path...
Nuget package:
https://www.nuget.org/packages/ASPNetWebAPIAntiXss/
Examples and the product page:
https://bitbucket.org/embarr-development/asp.net-web-api-antixss-attribute

What is a good design when trying to build objects from a list of key value pairs?

So if I have a method of parsing a text file and returning a list of a list of key value pairs, and want to create objects from the kvps returned (each list of kvps represents a different object), what would be the best method?
The first method that pops into mind is pretty simple, just keep a list of keywords:
private const string NAME = "name";
private const string PREFIX = "prefix";
and check against the keys I get for the constants I want, defined above. This is a fairly core piece of the project I'm working on though, so I want to do it well; does anyone have any more robust suggestions (not saying there's anything inherently un-robust about the above method - I'm just asking around)?
Edit:
More details have been asked for. I'm working on a little game in my spare time, and I am building up the game world with configuration files. There are four - one defines all creatures, another defines all areas (and their locations in a map), another all objects, and a final one defines various configuration options and things that don't fit else where. With the first three configuration files, I will be creating objects based on the content of the files - it will be quite text-heavy, so there will be a lot of strings, things like names, plurals, prefixes - that sort of thing. The configuration values are all like so:
-
key: value
key: value
-
key: value
key: value
-
Where the '-' line denotes a new section/object.
Take a deep look at the XmlSerializer. Even if you are constrained to not use XML on-disk, you might want to copy some of its features. This could then look like this:
public class DataObject {
[Column("name")]
public string Name { get; set; }
[Column("prefix")]
public string Prefix { get; set; }
}
Be careful though to include some kind of format version in your files, or you will be in hell's kitchen come the next format change.
Making a lot of unwarranted assumptions, I think that the best approach would be to create a Factory that will receive the list of key value pairs and return the proper object or throw an exception if it's invalid (or create a dummy object, or whatever is better in the particular case).
private class Factory {
public static IConfigurationObject Factory(List<string> keyValuePair) {
switch (keyValuePair[0]) {
case "x":
return new x(keyValuePair[1]);
break;
/* etc. */
default:
throw new ArgumentException("Wrong parameter in the file");
}
}
}
The strongest assumption here is that all your objects can be treated partly like the same (ie, they implement the same interface (IConfigurationObject in the example) or belong to the same inheritance tree).
If they don't, then it depends on your program flow and what are you doing with them. But nonetheless, they should :)
EDIT: Given your explanation, you could have one Factory per file type, the switch in it would be the authoritative source on the allowed types per file type and they probably share something in common. Reflection is possible, but it's riskier because it's less obvious and self documenting than this one.
What do you need object for? The way you describe it, you'll use them as some kind (of key-wise) restricted map anyway. If you do not need some kind of inheritance, I'd simply wrap a map-like structure into a object like this:
[java-inspired pseudo-code:]
class RestrictedKVDataStore {
const ALLOWED_KEYS = new Collection('name', 'prefix');
Map data = new Map();
void put(String key, Object value) {
if (ALLOWED_KEYS.contains(key))
data.put(key, value)
}
Object get(String key) {
return data.get(key);
}
}
You could create an interface that matched the column names, and then use the Reflection.Emit API to create a type at runtime that gave access to the data in the fields.
EDIT:
Scratch that, this still applies, but I think what your doing is reading a configuration file and parsing it into this:
List<List<KeyValuePair<String,String>>> itemConfig =
new List<List<KeyValuePair<String,String>>>();
In this case, we can still use a reflection factory to instantiate the objects, I'd just pass in the nested inner list to it, instead of passing each individual key/value pair.
OLD POST:
Here is a clever little way to do this using reflection:
The basic idea:
Use a common base class for each Object class.
Put all of these classes in their own assembly.
Put this factory in that assembly too.
Pass in the KeyValuePair that you read from your config, and in return it finds the class that matches KV.Key and instantiates it with KV.Value
public class KeyValueToObjectFactory
{
private Dictionary _kvTypes = new Dictionary();
public KeyValueToObjectFactory()
{
// Preload the Types into a dictionary so we can look them up later
// Obviously, you want to reuse the factory to minimize overhead, so don't
// do something stupid like instantiate a new factory in a loop.
foreach (Type type in typeof(KeyValueToObjectFactory).Assembly.GetTypes())
{
if (type.IsSubclassOf(typeof(KVObjectBase)))
{
_kvTypes[type.Name.ToLower()] = type;
}
}
}
public KVObjectBase CreateObjectFromKV(KeyValuePair kv)
{
if (kv != null)
{
string kvName = kv.Key;
// If the Type information is in our Dictionary, instantiate a new instance of that class.
Type kvType;
if (_kvTypes.TryGetValue(kvName, out kvType))
{
return (KVObjectBase)Activator.CreateInstance(kvType, kv.Value);
}
else
{
throw new ArgumentException("Unrecognized KV Pair");
}
}
else
{
return null;
}
}
}
#David:
I already have the parser (and most of these will be hand written, so I decided against XML). But that looks like I really nice way of doing it; I'll have to check it out. Excellent point about versioning too.
#Argelbargel:
That looks good too. :')
...This is a fairly core piece of the
project I'm working on though...
Is it really?
It's tempting to just abstract it and provide a basic implementation with the intention of refactoring later on.
Then you can get on with what matters: the game.
Just a thought
<bb />
Is it really?
Yes; I have thought this out. Far be it from me to do more work than neccessary. :')

Categories