This may be a philosophical question, but I thought I'd ask it here since I'm suffering from a bit of analysis paralysis.
I'm currently working on a browser based game (Client-side HTML/Javascript, and WCF Web Services to reach the backend) and I'm trying very hard to have a nice, rich Domain Model.
So here's my question. I have a class called Squadron
public class Squadron
{
public string SquadName { get; set; }
public User Owner { get; set; }
public int XPosition { get; set; }
public int YPosition { get; set; }
public int XTarget { get; set; }
public int YTarget { get; set; }
}
The Squadron is owned by a User
public class User
{
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public int UserID { get; set; }
public List<string> Roles { get; set; }
}
I also have a Squadron repository that returns a fully populated Squadron object, based on it's ID. I have a webservice (basically, GetSquadron) that should return the Squadron. However, the attached User object has some information that I probably don't want exposed to any client (Password, as an obvious example). Although it seems that Password should be a part of this Domain object...it doesn't seem like something I always want populated.
I've considered adding another layer of logic (after the Domain object has been populated) that will ensure that the calling user has access to certain fields, but I was wondering what best practices I can find in the community. I tried Googling but I haven't had much luck.
Thanks!
EDIT: Before anyone harps on it, the password is hashed. I never store a clear-text password in the database. I just figured that I probably shouldn't be returning the password, encrypted or not.
EDIT 2 (Phillip): I've populated the User object because I do need a couple of those fields down in the client side (Username and UserID, and possibly Email). Maybe creating some DTO's is the answer to the problem. I guess I thought it'd be nice to have a common model across all layers.
I would consider substituting the Owner (User) property for the UserID property. I don't see any real reason that you would need the entire User object in Squadron. However, I don't know your design or intent well. It is also a very bad practice to pass around a user password even if it's encrypted.
If you do need the Person details in the Squadron object I'd suggest creating a new Person view model that does not include the user Password.
I agree with PhillipPDX about not passing around the password, but I would be hesitant to use DTOs to pass data from a web service.
If I'm understanding that tech right, you would create the DTO, serialize the object which is then returned by the web service. Typical object serialization tends to carry a lot of overhead and results in larger amounts of data being returned from the service, and an object that requires .Net on the client side to deseralize the data back into an object (DTO).
A more modern approach would be to use something like NewtonSoft's JSON Serializer to convert the POCO (Plain Ol' C# Object) into a JSON string which is then returned by the web service. Since your game is browser / Javascript based JSON would be a natural fit for this use case.
Related
I have a method definition:
public async Task<IHttpActionResult> FindUsers([FromBody]User user)
This uses a class:
public class User
{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I would like to extend the functionality of this without breaking the existing endpoint for current clients.
All clients make requests to the RESTful endpoint using an instance of System.Net.Http.HttpClient. They accept the JSON response and deserialize it into a list of User instances:
var user = JsonConvert.DeserializeObject<User>(content);
I would like to add a property to the User class:
public IList<string> Countries { get; set; }
I do not want this to break the endpoint for existing clients. That is, I want them to be able to continue deserializing into instances of their User class without problems.
I would also like them to be able to deserialize into an updated version of the User class if they wish to take advantage of the updated functionality.
The extended functionality would be implemented in the endpoint. It would detect if the Countries list has been provided in the request and, if so, perform a different operation and, thus, return a response - one which includes the Countries list.
Is this possible to do without breaking the endpoint for existing clients?
In my experience, adding data like this is generally not a problem.
If you send the data to the client, there is no need for them to expect or use it.
They may not have a property to deserialise countries into, but that shouldn't be a problem.
They don't see it, don't use it, etc.
The signature of your method is not changing (you are still basically expecting a User object) so everyone could still use the same endpoint. If they happen to supply countries, then they will be deserialised into your newer model. If they don't supply countries, then that property will not be set.
It is then up to you to decide what to do based on whether that data is provided.
As you might expect, this is a rough answer based on my own experience.
Your situation may be (is likely) to be more complicated than expressed by the question, but hopefully this provide some help.
I would like to be able to expose a list of users using WebAPI 2. However since I am using the new Asp.Net Authentication framework in MVC5, I can't seem to find a way to only mark specific fields as DataMembers.
Heres what I have:
[DataContract]
public class ApplicationUser : IdentityUser {
public Nullable<DateTime> birthday { get; set; }
[DataMember]
public int tolerance { get; set; }
[DataMember]
public string twitter { get; set; }
}
However, that doesn't seem to work because IdentityUser doesn't have the [DataContract] attribute. I've tried creating a custom IdentityUser, but I haven't been able to build after creating a custom copy of IdentityUser.
Any tips or work arounds here? I'd prefer not to have to create a ViewModel, unless that's the current best practice.
I know this is an old question and I stumbled upon it when I was trying to achieve the same thing. Here's what I ended up doing. You could override your properties and mark them as [JsonIgnore] so that they won't get serialised automatically.
public class ApplicationUser : IdentityUser
{
public UserType UserType { get; set; }
[JsonIgnore]
public override string PasswordHash
{
get { return base.PasswordHash; }
set { base.PasswordHash = value; }
}
}
You probably should just send a different object with the user info you need as opposed to serializing the user object.
What formatter do you want to use? I don't see any issue with default Json formatter. But for xml serializer, it requires base class to be DataContract as well.
View model is always the best practice here, although most of the samples for web api are using data entity for simplicity. The two models are separate of concerns. View model represents the contract of your api and the data model represents your domain concept. Combining two models into one can impact your design decision or even more seriously, can cause security issues. Using data entity may expose unexpected data to user. For example, different formatters have different rules to control the exposure of model. JsonIgnore doesn't work in xml formatter. It will be more complicated if you have custom formatter. Especially for the identity user entity, which has many sensitive properties like pasword hash, security stamp. I won't recommend you expose it to public.
BTW, there is many mapper tools that can help to simplify the mapping from domain model to view model. You may need them: http://www.nuget.org/packages?q=mapper
Is it possible to have ApiMember attribute data show up on ServiceStack generated metadata for properties of complex types on the request DTO? If so, how can this be achieved?
Let's say I have a request DTO with the following properties:
public Customer Customer { get; set; }
public List<CustomerOrder> CustomerOrders { get; set; }
and a customer type with the following properties:
public string Id { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
I would like to be able to add the ApiMember attribute to the customer's properties. However, when I do so, the metadata page for the request DTO does not show the customer's properties.
I would also like the CustomerOrder's properties to be shown on the metadata page as well. I realize this could be a little trickier due to it being a list of the CustomerOrder type.
If this is not supported, recommendations for other options are welcome.
I don't think what you're looking for is supported at the moment. I think the Api and ApiMember attributes are meant to follow/mirror the Swagger API and DataTypes. In the Swagger API there is support for complex types but in order get the details of a complex type it needs to be in the models section of the API declaration. I don't think models is currently handled within ServiceStack. At least, I haven't stumbled across it within the code
I'm creating a system using ASP.NET MVC for filling out online job applications. It's really just an experiment to familiarize myself with the MVC framework. I'm definitely not a security expert so I just wanted to get some advice here since this web app will be dealing with sensitive information.
The system has a wizard-like set of views. You go from one view to the next filling out the relevant information until the end when you finally submit it.
Each job application is stored in the database with a GUID primary key. Right now I am simply storing that GUID in a hidden field in the view of each page. This makes it easy to update the model in the controller like so:
[HttpPost]
public ActionResult ExampleAction(FormCollection formValues)
{
Guid appId = new Guid(Request.Form["ModelId"]); // the GUID stored in the hidden field
ExampleModel example = db.Entities.Single(e => e.ModelId == appId);
UpdateModel(example, formValues);
db.SaveChanges();
return RedirectToAction("ExampleAction2", new { appId = appId.ToString() });
}
I know this is not secure because anyone with any kind of development experience knows you can edit the values of hidden fields in any browser's developer tools. So what's the recommended way to securely get the same results?
You should store it in the Session object. That way, you can call it at anytime from anywhere and it will never display on any of your views.
The doc: http://msdn.microsoft.com/en-us/library/ms178581.aspx
I know this has been answered, just for interest sake I want to leave another option. How you could go about it is parsing the information you get from the first view as a JSON string that you can store in a cookie and then later serialize it when you need it.
This is asuming that the information is safe to store client side. Otherwise it could be an encrypted cookie I suppose. This would address the concerns for cloud computing and load balancers etc.
Why not post to each step instead of using RedirectToAction? That way you can create a model that contains each step.. for example:
class JobApplicationViewModel
{
public Guid ApplicationGuid { get; set; }
public StepOne Step1 { get; set; }
public StepTwo Step2 { get; set; }
public int CurrentStep { get; set; }
}
The step 1 view can post to step 2.. for example:
[HttpPost]
public ViewResult StepTwo(JobApplicationViewModel viewModel)
{
ServiceLayer.Update(viewModel);
return View(viewModel);
}
Then, the StepTwo view posts to StepThree, StepThree posts to Step4, etc. This makes sense logically, as you're only allowing people to get to any step beyond step 1 by posting the form.
I have a method called GetObjectsRelatedToAType, e.g. GetCarsRelatedToDealership. Which approach is better from a web services or general method signature standpoint:
List<Cars> GetCarsRelatedToDealership( Dealership dealership );
or
List<Cars> GetCarsRelatedToDealership( id dealership );
I tend to like the object approach because it is a little more forceful about making sure the source input to the method is valid. Thoughts/advice?
Is the ID the only piece of information the method requires to function? If so I'd leave it at that.
The object approach has problems.
Dealership dealership;
GetCarsRelatedToDealership(dealership); // dealership is null
var dealership = new Dealership();
GetCarsRelatedToDealership(dealership); // dealership has no id
In these cases the object isn't giving you any advantage over just the id. The id might be wrong, but you can validate that. The object makes things a bit more complicated.
When dealing with services, I would create a Request / Response pair of classes. This allows you to ensure your signature never needs to change. Your Request or Response objects might change, but the method signature does not.
Now I can pass the dealership id, as well as who is requesting the information and ensure that the user asking is allowed to see the inventory of that dealership. Something just passing the dealership or id would not allow.
public class CarsRequest
{
public int DealershipId { get; set; }
public int RequesterId { get; set; }
}
public class CarsResponse
{
public Car[] Cars { get; set; }
}
CarsResponse GetCarsRelatedToDealership(CarsRequest request);
For the web services I try to minimize how much data is being sent over the wire. If you also need a method I would probably make member method "GetRelatedCars" for the "Dealership" class/interface. When the web service call comes you could validate it is a real "Dealership" (and the caller has rights to it) by getting that object based on the id and for the call the "GetRelatedCars" method on the object.
Can you have the method take an interface? This would make it much more flexible and perhaps easier to test.
List<Cars> GetCarsRelatedToDealership( IDealership dealership );
I'd go with the Id approach, and validate that the Id is valid. You could potentially get an invalid Dealership object, in which case there would be no advantage gained to using the Dealership
Using just an ID is usually sufficient, and is far easier because you can simply pass an ID around from one place to another. This is especially important with web services, where you want to minimize the amount of data being transferred.
However, if you often have large method signatures where the input is not specified very well by the name of the method:
List<Cars> GetCars(int makeId, int modelId, int year, int dealershipId);
... it can become very easy to pass the wrong ID in to the wrong place. That's the point where I would begin trying to find a different strategy. Strongly typing your inputs as domain objects is one solution, but it will generally cause you a lot more hassle than simply using a special options POCO:
public class GetCarsOptions
{
public int MakeId {get;set;}
public int ModelId {get;set;}
public int Year {get;set;}
public int DealershipId {get;set;}
}
List<Cars> GetCars(GetCarsOptions options)
{
ValidateOptions(options); // make sure the values all make sense.
}
The fact is, you won't be able to catch every possible error at run time, so it's a good idea to combine automated tests with "fail-fast" techniques to try to catch as many bugs as possible after compilation and before deployment.