In standard .NET MVC we have our Domain classes and we have ModelView classes. Now, with ASP.Net Web API I suppose there is no need for ModelView classes (since we are returning data) but should we return (serialized) Domain classes directly or there is a need for something in between?
// Domain class
public class User {
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
// inter class
public class ProductModel {
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public string FullName {get {return String.Format("{0} {1}", FirstName, LastName);}}
}
// Controller V1 returns Product
public class UserController : ApiController
{
public Product GetProduct(int id) {...}
}
// Controller V2 returns ProductModel
public class UserController : ApiController
{
public ProductModel GetProduct(int id) {...}
}
Exposing your domain model in a API is rarely a good idea.
If you are the only one who will be consuming the API and you can be sure that you will deploy updates to the client and the server at exactly the same frequency, then you may be able to take this shortcut, however, I wouldn't recommend it.
Related
I created a new MVC project and I ticked the box for API.
However, I intend to create many API functions and I don't really want to fill up the main controllers folder, so, I thought this will be a good use for an area.
So, I created an area called API, but, no matter what I do, I can't seem to access any of the API pages.
Just to test, I created another controller called test on the API area, and, I can access and do everything as expected.
I came straight from MVC2/3, and then had a few years off... I'm a bit out of touch and I believe this could be related to the /App_Start/WebApiConfig.cs and /Global.asax files, but, I have tried to edit them in various ways without any luck.
Does anyone know what is happening and what I need to do to get the API features working from an area?
You don't need to create an Area for Api controllers, but your Api controllers must derive from ApiController to be picked up. Instead of creating a Area, just organize your controllers inside folders and as long as the controllers follow convention they will be picked up by the WebApi.
In your WebApiConfig.csyou'll be able to define Routes, although I recommend using Attribute Based Routing instead. Then for each "area" you could create a base api controller and stick a `[RoutePrefix("api/areaName")] attribute on the class - and then for every controller in that area, you just derive from that base controller.
Here is a quick example for a "Users" api controller. With the example below you'll be able to to use the following urls:
GET http://localhost:port/api/users
GET http://localhost:port/api/users/some-guid
POST http://localhost:port/api/users
Remember to enable attribute based routing in your WebApiConfig class.
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
}
}
UsersApiController.cs
[RoutePrefix("api/users")]
public class UsersApiController : ApiController
{
List<User> _users = new List<User> { new User("Foo", "Bar"), new User("Bar", "Foo") };
[Route("")]
public IHttpActionResult Get()
{
var result = _users;
return Ok(result);
}
[Route("{id:guid}")]
public IHttpActionResult Get(Guid id)
{
var result = _users.FirstOrDefault(q => q.Id == id);
if (result == null)
return NotFound();
return Ok(result);
}
[Route("")]
public IHttpActionResult Post([FromBody]PostModel model)
{
// Process the input model
var user = new User(model.FirstName, model.LastName);
// Save user to database
_users.Add(user);
return Created<User>(Request.RequestUri + user.Id.ToString(), user);
}
public class PostModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class User
{
public User(string firstName, string LastName)
{
Id = Guid.NewGuid();
FirstName = firstName;
LastName = lastName;
}
public Guid Id { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
}
}
I am working on a risk monitoring application with a SQL DB in the background. I use EF 4 Database First. There is a "Position" class in the model, which models holdings in various types of assets. A position holds a reference to a "Contract" class. This "Contract" class serves as the base class for various types of financial contracts, such as "Investment".
The classes look as follows:
public class Position
{
public int ContractID {get;set;}
public DateTime PositionDate {get;set;}
public decimal MarketValue {get;set;}
}
public class Contract
{
public int ID {get;set;}
public string Description {get;set;}
public int CurrencyID {get;set;}
public Instrument Instruments {get;set;}
}
public class Investment:Contract
{
public int ID {get;set;}
public int BBGIndustryID {get;set;}
}
When i try to run a query and try to filter on properties from the "Investment" Class, the system throws an StackOverFlowException:
var dataPoint = _context.Positions.Where(c => c.Contract.Instruments != null).Where(c => c.Contract.Instruments.BBGIndustryID == 24).ToList();
How do i need to write the query that i can filter on properties from the derived classes, or do i need to move the properties i need to filter on to move to the base class?
Suppose I post an object like this
{"Dto" : {
"DtoId" : 1,
"DtoThing" : "Some value",
"DtoChildStuff" : [{"CsId" : 1, "ChildProperty" : "SomeThing"}]
}}
to a WebApi action like this
[HttpPost]
public Response<MyDto> Post(DtoWrapper<MyDto> input)...
where the parameter is just some object with a property MyDto of type MyDto, and MyDto is like this
[DataContract]
public class MyDto
{
[DataMember]
public int DtoId {get;set;}
[DataMember]
public string DtoThing {get;set;}
[DataMember]
public List<ChildStuffDto> DtoChildStuff {get;set;}
}
[DataContract]
public class ChildStuffDto
{
[DataMember]
public int CsId {get;set;}
[DataMember]
public string ChildProperty {get;set;}
}
and (by the way) the DtoWrapper is just
public class DtoWrapper<T>
{
public T Dto {get;set;}
// So that I can add some other info that I need //
}
Why can't the action see any child objects. If I change the type on the parameter to object, I can see the child object being posted in, but it doesn't get deserialised. Any ideas?
Ok here's my answer, but I'd love to know if there's a way I can get it to happen without adding this line of code to my action.
public Response<MyDto> Post(object input)
{
dynamic myWrapperObj = JsonConvert.DeserializeObject<SomeWrapperForMyDto>
(input.ToString());
...
If that's how it has to be then fair play, but it seems a shame. Thanks for any posts :)
I'm using asp.net mvc4 and json.net
and i have a json structure like http://api.domaintools.com/v1/domaintools.com/whois/
How can i deserialize it into my own class ? This looks a bit complicated structure to me to realize how to build my class ?
Nam Vo
You can use the following class structure:
public class Response
{
public string Registrant {get;set;}
public Registration registration {get;set;}
public WhoIs whois {get;set;}
}
public class Registration
{
public DateTime created {get;set;}
public DateTime expires {get;set;}
public DateTime updated {get;set;}
public string registrar {get;set;}
public List<string> statuses {get;set;}
public List<string> name_servers {get;set;}
}
public class WhoIs
{
public DateTime date {get;set;}
public string record {get;set;}
}
You can then do like below:
Response response = JsonSerializer.DeserializeFromString<Response>(data);//data is your data from the link you have given in the problem description
Thus the data is now deserialized into your own class Response...hope this helps....
My application has products and vendors and both of them have similar items in a "has a" relationship...in particular they have a "favorite" so users can bookmark them.
so we have:
public class Product
{
public int ProductId {get;set;}
public int Name {get;set;}
public List<Favorite> Favorites {get;set;}
}
public class Vendor
{
public int VendorId {get;set;}
public int Name {get;set;}
public List<Favorite> Favorites {get;set;}
}
public class Favorite
{
public int FavoriteId {get;set;}
public string UserName {get;set;}
}
At first this didn't work, so I added:
public int? VendorId {get;set;}
public int? ProductId {get;set;}
Now the issue I'm having is that my Vendor.Favorites and Product.Favorites are always null.
How do I bind these so that I can work with the objects like that? Do I not make it a separate entity?
Thanks!
UPDATE: I should note that I'm using MVC 3 Code-first with POCO.
UPDATE: Solution:
I don't think this is ideal, still working out the kinks with how I want this to work because It will add redundant code for adding favorites and reviews.
public class Product
{
public int ProductId {get;set;}
public int Name {get;set;}
public virtual List<Favorite> Favorites {get;set;}
}
public class Vendor
{
public int VendorId {get;set;}
public int Name {get;set;}
public virtual List<Favorite> Favorites {get;set;}
}
Having the raw nullable int variable in the favorites class makes it work, but if I wanted to use the favorites class with other objects I'll have to modify the favorites properties with a new mapping to the key of the object. Out of curiosity, when dealing with these classes normally, how do you manage the data storage for these objects? I'm assuming you deal with it at a DAL?
You could use inheritance, make a base class containing only Favorite then derive classes based on that for the other info. This establishes an "is a" relationship
Ex.
public class baseClass
{
public list<Favorite> Favorites { get; set;}
}
public class Product : base
{
public int ProductID { get; set; }
public string Name { get; set; }
}
Then a Product Object would have all 3 properties.
Based on the assumption that you're using EF 4.1:
Your model looks pretty good except I'd change
public int? VendorId {get;set;}
public int? ProductId {get;set;}
to
public virtual Vendor VendorId {get;set;}
public virtual Product ProductId {get;set;}
Then your FK relationships should be all set. By my understanding of EF, List<Favorite> is meant to establish a relationship and is not actually populated. You have to populate it yourself, either by calling .Include() on the context or by referencing the actual FK that EF creates in the database, which in your case would be VendorId_FavoriteId or ProductId_FavoriteId
I would keep one Property to store the ID's (either VendorID or ProductId) and use another property to tell me what type it is (Vendor or Product)
public class Favorite
{
public int FavoriteId {get;set;}
public string UserName {get;set;}
public int ItemID { set;get;} //can use a better generic name
public FavoriteType Type { set;get;}
}
I have an Enum for the Types
public enum FavoriteType
{
Vendor,
Product
}
And make sure you are initializing your sub properties before accessing them / applying a method on those so that It won't throw the null reference exception!. You can do it constructor itself
public class Product
{
public int ProductId {get;set;}
public int Name {get;set;}
public List<Favorite> Favorites {get;set;}
public Product()
{
if(Favourites==null)
Favorites=new List<Favorite>();
}
}