ASP.NET MVC - Complex Objects and Forms - asp.net

So let's say we have a domain object such as the following
public class Person
{
public string Name { get; set; }
public IList<PhoneNumber> PhoneNumbers {get; set; }
public IList<Address> Addresses { get; set; }
}
The Person is not valid until a name, phone numbers, and addresses have been entered. How do you guys handle this using ASP.NET MVC and forms...
I was thinking you could serialze the Person to session and have multiple views for editing Name, adding phone numbers, adding addresses - the controller actions would modify the person in the session and a final Save action would push to database.
I don't really like having multiple views and using the session. Another option would be to have a single very complex form that could have "dynamic" sections of elements for adding/removing phone numbers, addresses within the browser prior to posting to the save action.
What is everyone doing with complex objects and editing via forms?
Thanks!

I would usually use the "dynamic section" route.
However, I would not make your validation so strict that the user is unable to save work in progress. A list of phone numbers, addresses, etc., can take quite a while to enter. It is beneficial to the end-user to be able to save their work from time to time in case they lose Internet connectivity or something. It's probably a good idea to save the records automatically via AJAX from time to time if your data entry form is quite large. (Like Gmail.) Therefore, your model should allow them to save incomplete work from time to time, and run the whole validation only when they say they are "done."

Related

Best practice to implement sending message to custom groups in SignalR

I am developing a real time multiplayer game using SignalR. The message delivery logic is not very simple which I could not handle it by using Groups.
For example, one message will be delivered to users with some custom property equals to some dynamic value. It means the target audiance can not be handled by
Clients.All
Clients.AllExcept
I have a mapping class something like this:
public class Player
{
public dynamic Client { get; set; }
public string ConnectionId { get; set; }
public string Name { get; set; }
}
Somehow I do detect all my audiences in a List object.
What is the best way to send message to everyone in the list? Enumerating through list and calling
foreach (var loopPlayer in players)
{
player.Client.sendMessage(message);
}
Or
List<string> ids = new List<string>();
foreach (var loopPlayer in players)
{
ids.Add(item.ConnectionId.ToString());
}
Clients.Clients(ids).sendMessage(message);
My concern about the first one is, it will serialize the message every time. About the second one, I don't know how it is working behind the scene.
The both approach is working but I am concerning about performance and trying to find the best practice. Or which any other approach I might use?
As you said, enumerating over list of clients serialize message each and every time (and store those serialized messages in internal buffers etc etc). If message is same, this is unnecessary CPU\memory overhead.
Clients.Clients(ids) serializes message only once so performance vise, its definitely way to go.
The message delivery logic is not very simple which I could not handle it by using Groups. For example, one message will be delivered to users with some custom property equals to some dynamic value.
Groups work in scaleout scenario out of the box which is huge benefit if you ever find yourself in need to scaleout. So maybe try to find some way to simplify "group assigment logic" even at cost of delivering some messages to more clients and doing "filtering" client side...

Best Way to Write an Asp.Net Web Service To Play Well In the Wild

I am writing an API for my ASP.NET application that other developers will use. The API will basically return a list of people with their first name, last name, and id. There are lots of ways to write web services in ASP.NET, the easiest probably being create a web service function (asmx) that returns a DataTable. This is simple enough for other .NET developers to deal with, but I am not convinced that this is the best way to write a web service for general platform and language independence.
What is the currently accepted standard to write a web service like this that plays well in the wild today?
Some ideas that come to mind from experience:
Use WCF, not .asmx. WCF does all the same things that ASMX files do, and is generally the replacement for ASMX services (see here and here).
Write methods using simple POCO data types, like List<Person> rather than DataTable. Basic types serialize more easily and will make more sense in other programming environments since you want your service to be language independent.
Provide generic CRUD methods for managing data. Depending on how your service will be consumed, if the user needs to modify data, a simple method is to provide getBlah(), updateBlah(obj newObj), deleteBlah(obj objToDelete), etc. that use the same data types.
Hide the details that the service consumer doesn't need to know, rather than just blindly exposing all of your data types, structures, and field names as-is. This will make your service more robust for handling internal changes, and you can simplify and control what the end-users see. For instance, if you have a Person class with 30 properties, and only 5 are relevant to the end-user, provide a class that interfaces between Person and a PersonSimple class which is exposed. Without this layer, your end-users will have to modify your code every time you change your data structure, and you will be locked down by this tight coupling.
If security is important
Execute your service over SSL. This protects data transfered over the wire from being sniffed.
Use authentication, either with a Login method and session, or SOAP headers. Services by default are anonymous unless there is some sort of authentication scheme. Even if you think nobody will find your service because you only provide the URL to your users, it will get out somehow, somewhere, and people will try to misuse the service when it does. Plus, you can control who can do what by different logins and authorization schemes.
I am currently working on a similar issue: A web api service in .NET that receives data tables as input parameters, apply some operations on them (using Table Valued Functions), and return some output data tables.
In your case, you don't need to use a complex class like DataTable; you could use an array (List<>) of a simple class with fields like first name, last name and id. Using Web Api of ASP.NET you could do something like the following:
1) Create a new WebApi project in Visual Studio: For example (in VS 2012) C# > Web > ASP.NET MVC 4 Web Application > select "Wep Api" as project template
You will see a VS project with lots of folders, including one named Models
For help see: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
2) Create a new model code file Person.cs with a class like the following:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string[] Friends { get; set; }
}
3) Create e new controller code file PersonController.cs with methods for getting, inserting and updating records of the database. All the necessary serialization/deserialization (JSON and XML) and data binding is done automatically by the Web Api environment set by the project template.
// Get all the records of persons
public IList<Person> Get()
{
// read database into a list of persons (List<Person>)
// return List<Person>
}
Return record of a selected person:
public Person Get(int id)
{
// read database for a selected person
}
Parameter binding (reading a JSON/XML content sent by http POST into an object, or into a list objects) is also done automatically, as easy as the following:
// parameter binding: Create a Person object with content from XML/JSON
public void ReadPerson(Person p)
{
Trace.WriteLine(Person.Id);
}
public void ReadPersonList(List<Person> plist)
{
Trace.WriteLine(plist.Count);
}

Object property validation in MVC (using web service)

I have an ASP.Net MVC site, which connects to a web service.
The site's view model contains objects for each group of required service data AccountDetails (containing AccountId, AccountType, etc.), ContactDetails (containing Name, Address, etc.) and so on.
The service has a 'CreateUser()' method that accepts these objects as parameters, and it then performs all the validation itself - handing back an Object which has an array of any errors that have been found, including the name of the specific property/field.
I would like to know if there is a way of passing this returned error data into either DataAnnotations or something else.
I specifically can't write the conditions in the model itself, because the validation conditions within the web service are open to change at any moment - and we want this to dictate what fails and what succeeds.
== FURTHER INFO FOR MAKE IT A BIT CLEARER ==
Imagine I were locally (within the View Model) creating the ContactDetails class, I could very simply do this
public class ContactDetails
{
[IsRequired()]
[CustomAttributeofSomekind]
public string FirstName { get; set; }
public string LastName { get; set; }
}
However in this scenario - if we wanted to change the validation critera for whatever reason we would have to change it in both the web service AND in all the client websites that access the service.
We don't want to have to do this - instead I if (in the above) scenario ContactDetails.LastName is suddenly required and must be no more than 10 characters - this should only need updating in the web service.
I think you have two options:
Create a User class to wrap the CreateUser() method and add the DataAnnotations to that (this is what I would do, it allows you to go strongly-typed.)
Call the CreateUser() method directly from the controller Action and use server-side validation. Add each validation error in the CreateUser() result to the ModelState.Errors collection when any validation rules are violated.

Thoughts on writing a "flexible" API?

I may have the wrong "pattern" here, but I think it's a fair topic.
I have an ASP.Net MVC application in which it calls out to a WCF service to get back the ViewModels that will be rendered. (the reason it's using a WCF service is so that other small MVC apps may also call on for these ViewModels...only internally, it's not a publicly available thing so I can change anything either side of the service. The idea is to move the logic that was in the website, closer to the server/database so the roundtrips aren't so costly - and only do one roundtrip overall from the webserver to the database server).
I'm trying to work out the best thing to return these "ViewModels" in from the service. There are lots of common little bits of functionality, but each page may want to display different subsets of these things (so homepage maybe a list of tables, next page, a list of tables and users that are available).
So what's the best way of returning the information that the page wants, hopefully without the webservice knowing about the page?
Edit:
It's been suggested below that I move the logic in process. This would be a lot faster, except that's what we're moving away from because it is actually a lot slower (in this case). The reason for this is that the database is on one server, and the webapp is on another server, and the webapp is particularly chatty at points (there are pages it could end up doing 2K round trips - (I have no control over reducing this number before that's suggested)), so moving the logic closer to the db is the next best way of making it more performant.
I would look at creating a ViewModel per each MVC app/view. The service could just return the maximum amount of data for the "view" in a logical sense and each MVC app uses the information it wants when composing the ViewModel for it's view.
Your service is then only responsible for one thing, returning data specific to a view's function. The controller of each app is responsible for using/not using pieces of the returned data.
This will be more flexible as your ViewModels may require different validation rules as well. ViewModels also have MVC-specific needs(SelectList etc..) that shouldn't really be returned by a service layer. It seems like something can be shared at a glance, but there are generally lots of small differences that make sharing ViewModels a bad idea.
class MyServiceViewResult
{
public int SomethingEveryViewNeeds { get; set; }
public bool OnlyOneViewMightNeedThis { get; set; }
}
class ViewModel1
{
public int IdProperty { get; set; }
public ViewModel1(MyServiceViewResult result)
{
IdProperty = result.SomethingEveryViewNeeds;
}
}
class ViewModel2
{
public int IdProperty { get; set; }
public bool IsAllowed { get; set; }
public ViewModel2(MyServiceViewResult result)
{
IdProperty = result.SomethingEveryViewNeeds;
IsAllowed = result.OnlyOneViewMightNeedThis;
}
}
Instead of having a web service, why don't you just implement the service as a reusable library that encapsulates the desired functionality?
This will also allow you to use polymorphism to implement customizations. WCF doesn't support polymorphism in a flexible way...
Using an in-proc service will also be a lot faster.
See this related question for outlines of a polymorphic solution: Is this a typical use case for IOC?

Suggestions In Porting ASP.NET to MVC.NET - Is storing SiteConfiguration in Cache RESTful? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been tasked with porting/refactoring a Web Application Platform that we have from ASP.NET to MVC.NET. Ideally I could use all the existing platform's configurations to determine the properties of the site that is presented.
Is it RESTful to keep a SiteConfiguration object which contains all of our various page configuration data in the System.Web.Caching.Cache? There are a lot of settings that need to be loaded when the user acceses our site so it's inefficient for each user to have to load the same settings every time they access.
Some data the SiteConfiguration object contains is as follows and it determines what Master Page / site configuration / style / UserControls are available to the client,
public string SiteTheme { get; set; }
public string Region { private get; set; }
public string DateFormat { get; set; }
public string NumberFormat { get; set; }
public int WrapperType { private get; set; }
public string LabelFileName { get; set; }
public LabelFile LabelFile { get; set; }
// the following two are the heavy ones
// PageConfiguration contains lots of configuration data for each panel on the page
public IList<PageConfiguration> Pages { get; set; }
// This contains all the configurations for the factsheets we produce
public List<ConfiguredFactsheet> ConfiguredFactsheets { get; set; }
I was thinking of having a URL structure like this:
www.MySite1.com/PageTemplate/UserControl/
the domain determines the SiteConfiguration object that is created, where MySite1.com is SiteId = 1, MySite2.com is SiteId = 2. (and in turn, style, configurations for various pages, etc.)
PageTemplate is the View that will be rendered and simply defines a layout for where I'm going to inject the UserControls
Can somebody please tell me if I'm completely missing the RESTful point here? I'd like to refactor the platform into MVC because it's better to work in but I want to do it right but with a minimum of reinventing-the-wheel because otherwise it won't get approval. Any suggestions otherwise?
Edit: Areas?" Would it be a viable option to use ASP.NET MVC 2 Areas, where each Area represents a different site, complete with css, javascript, etc.?
I agree with the accepted answer. Because this answer did not explicitly go into your question about being RESTful or not I would like to add something about that (1). And also go into your question about area's (2).
0. MVC.NET?
But first I want to say that for MVC.NET, the official term is ASP.NET MVC. With ASP.Net you probably meant ASP.NET Webforms. The full terms more clearly indicate MVC is still just an extension of ASP.NET. Then it's less of a surprise that you can also mix and match MVC views and 'old' .aspxpages in one and the same project, if you so choose. This CAN be an easy way to port a project from WebForms to MVC, by allowing stuff to migrated step-by-step over a periodand getting new stuff out there e.g. the Agile way. Note to be careful to update routing/URL's for users/SEO as you go).
1. Using cache
Using the cache for per-domain customization is indeed RESTful enough. I assume you mainly had question about 'stateless' property of true RESTful services. Only if you also did per-user customization with your SiteConfiguration object would you violate that. When config only differe changes per domain, the state/config is in-a-way encapsualted in the URL (e.g. the domain name) so the state/config travels to and from the user, and your service itself is stateless.
Also using .NET's Cache object as you propose instead of an alternative like the Application object has some advantage according to this SO article.
I personally dislike using the cache for basic acrchitectural things however, because it is untyped. So you have to cast all stuff from the cache. I'm nitpicking here because you have only one big configuration object, so this only has to be done once, and all the stuff in it is nicely typed. But still..
The site I've been working on lately also has per domain customization, but that is basically just the language the site is shown in. So directly at the beginning of each request (global.asax's Begin_Request) we simply set the current CultureID on the CurrentThread (this thread handles the incoming HTTP request for one domain, and serving the response). We can then show english for our-domain.com, French for our-domain.fr, etc. So the culture has a direct one to one mapping with the domain of the current URL. Localization logic can then be done using .resx files. We also have some limited conditional logic on this current cultureID spread throughout our code to allow having some parts being not available, or sending localized e-mails and other not directly request related stuff.
Long story, but spreading the per-domain specifics/config throughout your code in a similar way, based on current domain, would be an alternative. But this would not really reuse the existing logic as you say you wanted. SO I will mention one last alternative.,
You could use your existing SiteConfig class but then use a set of simple static variables (instances of the SiteConfiguration class) for each configuration type that you have. That way everything is neatly typed. You can map the domain name in the URL to the matching static configuration object at the beginning of each request as I indicated, and then access the config of the current request. That is assuming you have a managable number of sites, that are each quite distinct, and that and you don't have to be able to load configuration dynamically from a database or something. Note that using static variables they can still be loaded at app startup from either DB, or from web.config/appSettings (or something else). When you use web.config/appsettings it has the advantage that the site would automatically reload/restart with the new config when you change it.
2. Using Area's
About using area's for different sites instead of different domains. It depends on what you want. But I see area's more for allowing having different parts on one site, that are functionally different. E.g. that don't have much in common and therefore don't share any generic code. Area's basically allow you to put a group of somehow related controllers, models and views into one area of the site. And then via area routing, separate the different functionalities within one part of the site that is apparent to users also via starting with the same URL.
From what you say, it seems meer that all your sites share the same generic code, but are just customized through some configuration. So I don't think area's match your problem.
Setting this information in your cache is just fine but anytime your application recycles it will need to be reload which usually isn't a problem. I think this follows the model since each request is providing you with the info you need to pull from the cache since it is based on the requests domain and you don't really need to look it up in a DB or make a costly call to build it except for the first time.
You could also consider moving this data to your web.config file but I am assuming there is one site with many domains pointing to it that you want to customize?
Just make sure your indexing the cached data with the site it's associated with and accessing by that index because all domains pointing to one app will use only one cache.

Resources