MVC2 controller method that can accept unknown number of variables? - asp.net-mvc-2

I need to work with the below posted data, or a variant thereof. Basically, I need to post a variable number of key-value pairs that represent a question id and answer string.
How do I write an ASP.NET MVC2 controller method signature to accept an unknown number of key-value pairs?
attachmentId=8809&question_712=&question_713=&question_714=&question_715=&question_716=&question_717=&question_719=&question_720=&question_721=&question_722=&question_723=&question_724=&question_725=&question_726=&question_727=&question_731=&question_738=&question_739=&question_741=&question_742=&question_743=&question_744=&question_745=&question_746=&question_747=&question_748=
Please note that in this example, there are 26 question keys with empty values. There may be more or less keys and they may or may not have a value. I can reformulate the way the data is sent by the client, so if the best solution is to rethink the way it is sent, I'm open to that.

This is basically the data a FormCollection collects. It's used in the automatically generated controllers by default. i.e. public ActionResult Edit(int id, FormCollection collection)

Use an array. The default modelbinder can detect arrays.
model.questions[0].key model.questions[1].value and so on for the html tag names then build an object that follows those conventions.
public class QuestionUpdateModel{
public int attachmentID{get;set;}
public QuestionPair[] Questions{get;set;}
}
public class QuestionPair{
public int key{get;set;}
public string value{get;set;}
}
After that your controller should accept an argument of QuestionUpdateModel type. The modelbinder should take care of the rest. Make sure you index them sequentially so it can create the array without null entries.

Related

MongoDB C# Select specific columns

I know that MongoDb C# driver doesn't support projections so I searched a little bit and I found that many people uses a mongoCursor to perform such queries, I'm trying to select only specific fields and my code is the following:
public T GetSingle<T>(Expression<Func<T, bool>> criteria,params Expression<Func<T, object>>[] fields) where T : class
{
Collection = GetCollection<T>();
return Collection.FindAs<T>(Query<T>.Where(criteria)).SetFields(Fields<T>.Include(fields)).SetLimit(1).SingleOrDefault();
}
I got and custom repository for users on top of that:
public User GetByEmail(string mail, params Expression<Func<User, object>>[] fields)
{
return GetSingle<User>(x=>x.Email==mail,fields);
}
this is the usage:
_repository.GetByEmail(email, x=>x.Id,x=>x.DisplayName,x=>x.ProfilePicture)
but I'm getting the fields included in the parameter but also all the Enums,dates and Boolean values that are part of the class User, the values that are string and not included in the field list are null so that's fine
what can I do to avoid that?
By using SetFields, you can specify what goes through the wire. However, you're still asking the driver to return hydrated objects of type T, User in this case.
Now, similar to say an int, enum and boolean are value types, so their value can't be null. So this is strictly a C#-problem: there is simply no value for these properties to indicate that they don't exist. Instead, they assume a default value (e.g. false for bool and 0 for numeric types). A string, on the other hand, is a reference type so it can be null.
Strategies
Make the properties nullable You can use nullable fields in your models, e.g.:
class User {
public bool? GetMailNotifications { get; set; }
}
That way, the value type can have one of its valid values or be null. This can, however, be clumsy to work with because you'll have to do null checks and use myUser.GetMailNotifications.Value or the myUser.GetMailNotifications.GetValueOrDefault helper whenever you want to access the property.
Simply include the fields instead this doesn't answer the question of how to it, but there are at least three good reasons why it's a good idea to include them:
When passing a User object around, it's desirable that the object is in a valid state. Otherwise, you might pass a partially hydrated object to a method which passes it further and at some point, someone attempts an operation that doesn't make sense because the object is incomplete
It's easier to use
The performance benefit is negligible, unless you're embedding huge arrays which I would suggest to refrain from anyway and which isn't the case here.
So the question is: why do you want to make all the effort of excluding certain fields?

How to specify different cache keys on the same key object in simple-spring-memcached

I am trying to implement a distributed cache with spring-memcached. The docs suggest that
to use an object as the key I need to have a method in my domain class with #CacheKeyMethod
annotation on it.
But the problem is I am using the same domain class in different scenarios and the key to be generated in each case has different logic. For examples for a User class one of the scenarios requires the key to be unique in terms of city and gender and but in the other case it requires to be unique in terms of the user's email, it's essentially what your lookup is based on.
Although a user's email would determine the city and gender, so I can use email as the key in first case as well but that would mean separate cache entries for each user while the cached data would be same as long as the gender and city are same, which is expected to increase the hit ratio by a huge margin(just think how many users you can expect to be males from bangalore).
Is there a way I could define different keys. Also it would be great if the logic of
generating the key could be externalised from the domain class itself.
I read the docs and figured out that something called CacheKeyBuilder and/or CacheKeyBuilderImpl could do the trick but I couldn't understand how to proceed.
Edit..
ok.. I got one clue! What CacheKeyBuliderImpl does is, it calls the generateKey method on defaultKeyProvider instance which looks for #cachekeyannotation on the provided domain class's methods and executes the method found to obtain the key.
So replacing either the CacheKeyBuilderImpl with custom Impl or replacing KeyProvider's default implementation within CacheKeyBuilderImpl with yours might do the trick... but the keyprovider reference is hardwired to DefaultKeyProvider.
Can anybody help me implement CacheKeyBuilder(with respect to what different methods do;the documentation doesn't clarify it) and also how do I inject it to be used instead of ususal CacheKeyBuilderImpl
Simple Spring Memcached (SSM) hasn't be designed to allow such low level customization. As you wrote one of way is to replace CacheKeyBuilderImpl with own implementation. The default implementation is hardwired but it can be easily replaces using custom simplesm-context.xml configuration.
As I understand your question, you want to cache your User objects under different keys depends on use case. It's supported out of the box because by default SSM uses method argument to generate cache key not the result.
Example:
#ReadThroughMultiCache(namespace = "userslist.cityandgenre", expiration = 3600
public List<User> getByCityAndGenre(#ParameterValueKeyProvider(order = 0) String city, #ParameterValueKeyProvider(order = 1) String genre) {
// implementation
}
#ReadThroughSingleCache(namespace = "users", expiration = 3600)
public User getByEmail(#ParameterValueKeyProvider String email) {
// implementation
}
In general the #CacheKeyMethod is only used to generate cache key if object that contains the method is passed as a parameter to the method and the parameter is annotated by #ParameterValueKeyProvider

MVC2 Action to handle multiple models

I've been looking around for an answer to this, which I can't believe hasn't been asked before, but with no luck I'm attempting here.
I have a signup form which differs slightly based upon what type of participant the requester is. While writing tests for the solution, I realized that all actions did the same things, so I'm attempting to combine the actions into one using a strategy pattern.
public abstract class BaseForm { common properties and methods }
public class Form1 : BaseForm { unique properties and overrides }
....
public class FormX : BaseForm { unique properties and overrides... in all about 5 forms }
Here is the combined action:
[ModelStateToTempData, HttpPost]
public ActionResult Signup(int id, FormCollection collection)
{
uiWrapper= this.uiWrapperCollection.SingleOrDefault(w => w.CanHandle(collection));
// nullcheck on uiWrapper, redirect if null
var /*BaseForm*/ form = uiWrapper.GetForm(); // Returns FormX corresponding to collection.
this.TryUpdateModel(form, collection.ToValueProvider()); // Here is the problem
form.Validate(this.ModelState); // Multi-Property validation unique to some forms.
if (!this.ModelState.IsValid)
return this.RedirectToAction(c => c.Signup(id));
this.Logic.Save(form.ToDomainClass());
return this.RedirectToAction(c => c.SignupComplete());
}
The problem I'm having is that TryUpdateModel binds only the common properties found in BaseForm. My previous code used public ActionResult FormName(int id, FormX form) which bound properly. However, I did some testing and discovered that if I replace var form with FormX form the form binds and everything works, but I'm back to one action per form type.
I'm hoping to find a way to get this to bind properly. form.GetType() returns the proper non-base class of the form, but I'm not sure of how to grab the constructor, instantiate a class, and then throw that into TryUpdateModel. I know that the other possibility is a custom ModelBinder, but I don't see a way of creating one without running into the same FormBase problem.
Any ideas or suggestions of where to look?
I was trying to do something similar to Linq, I was trying to create a class that would inherit some standard fields (ID, etc). I found that the default Linq engine would only use fields from the instantiated class, not from any inherited classes or interfaces.
To construct a Type simply use code like:
var form = Activator.CreateInstance(uiWrapper.GetForm());
I figured it out!
Erik's answer wasn't the solution, but for some reason it made me think of the solution.
What I really want form to be is a dynamic type. If I change this line:
dynamic form = uiWrapper.GetForm();
Everything works :)
On top of that, logic.Save(form.ToDomainClass()) also goes directly to Save(DomainTypeOfForm) rather than Save(BaseDomainForm) so I can avoid the headache there as well. I knew that once I figured out the problem here I could apply the answer in my logic class as well.

How to use ModelState.IsValid with complex objects?

I'm using NHibernate and I've got a Campaign class and it has a Client class as one of its members and I'm attempting to use ModelState.IsValid in my [HttpPost] public Create (CreateCampaignViewModel vm) method.
As my ViewModel contains the object Campaign ModelStats.IsValid is always false as I'm passing the Client.Id from the form instead of the entire Client object.
Is there a way to have it load the Client member before it runs the validation code that sets ModelState.IsValid? Or is there a way to refresh the state of ModelState after I 'manually' retrieve the client object based on the ClientId and bind it to the Campaign?
You probably want to add an attribute to the parameter of your action method, to disable binding of the Id:
[HttpPost]
public Create([Bind(Ignore="ClientId")]CreateCampaignViewModel vm)
Steven Sanderson has a blog post on just this. He removes any of the items which do not have incoming values from the errors collection.
http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/
Try using one of the overloads on the controller's UpdateModel method. Then call ModelState.IsValid.
I believe SharpArch has a modelbinder that can load the NH objects. But, I don't like that idea very much...instead I'd use a separate PostModel to hold the posted form values. If you re-use the ViewModel to also hold the post data, you'll usually have a lot of fields that make no sense to be posted (like the Client object in your example) or readonly display fields.
class CampaignPostModel{
...
public int ClientId { get; set; }
}
All you need to do is match-up the property names to the form input names and add this as a parameter on your post action method.

Is there a standard term for a class that contains just data, no logic?

I'm looking for a standard way to communicate to another programmer that a class is a essentially just a data container.
Take this simple User class for example:
class User
{
public string userName { get; set; }
public string passPhrase { get; set; }
public Role role { get; set; }
}
"That component makes use of the User class, which is just a (insert here) class."
I want to say "data model", but I think that's too broad. Classes described as data models often have logic.
Sometimes these are called DTOs - Data Transfer Objects.
POD - Plain Old Data
How about: struct ?
"Value object" is more precise in this case than is "Data Transfer Object". A value object contains just values; a Data Transfer Object additionally should implement a method for transferring that data to or from itself to or from some other entity. "Bean" is also an accepted term particularly within Java circles.
POXO - Plain Old X Object, where X is the language of your choice. Your case, seems like C#, so that's a POCO: Plain Old C# Object.
In Java a class with only properties and getters/setters for each property is called a bean or POJO (Plain Old Java Object)
Data Transfer Object more commonly referred to as a DTO.
This isn't standard, but I often attach the "Info" suffix to a class name to indicate that the class is just meant to store and transfer information. So I would change your User class to UserInfo.
UserData would work, too, as would a "don't add any methods to this damn thing" comment at the top.
Data Transfer Object may be correct, depending on the intent. It's essentially a container, but "container" is overloaded and generally refers to collection types.
Value Objects can have behavior, but if you have two independently created value objects with the same field values, and they can be treated as equivalent (e.g. the identity of the record doesn't matter), you could say that what you have is a value object. But usually Value Objects are best when immutable.
When there are a lot of Data Transfer Objects in a design, the design is sometimes pejoratively referred to as an Anemic Domain Model.
From A Gentle Introduction to Haskell
"A type like this is often called a tuple type, since it is essentially just a cartesian product of other types."
Data Object, Data Transfer Object, DTO