I am totally stuck. After searching for days, I finally decided to put my problem in front of you guys.
I need to develop a web api (using ASP.NET Web API 2) that would be used internally by a phone app and a web site. But I don't know how to design these specific cases:
1) Budget:
Budget Object:
public class Budget
{
public int Id { get; set; }
public string Name { get; set; }
public decimal TotalAmount { get; set; }
public decimal PendingAmount { get; set; }
public decimal ApprovedAmount { get; set; }
public decimal PaidAmount { get; set; }
public List<DepartmentBasicInfo> AvailableToDepartments { get; set; }
public string CurrencyCode { get; set; }
}
Budget Api controller:
public IHttpActionResult Get([FromUri]Models.BudgetModels.BudgetQueryModel query) {
return Ok(budgets);
}
The problem is all the Amount fields are calculated (not present in the database). The budgets need to return these when listed on the web page.
Then there are other web pages that would need a drop down list where it need to show budget name and currency and I do not want to calculate the budget amounts as this is a huge overhead in this case.
so the questions are:
1) As this is an internal web api, would this make sense to create two separate actions where one will return the whole Budget object and the other will return a thin Budget object (without Amounts and AvailableToDepartments properties) where calculations are not required, if yes what should be the route url?
2) Is there any clean way to able to use the same Budget class both for create and update in API because I am thnking that calculated fields do not belong to these operations.
3) Is it a good idea to pass a parameter to the Get method so it does not calculate budgets?
What is the cleanest way to handle these kind of cases? Please keep in mind that this is for an internal use api.
Thanks!
Iffi
Related
I'm creating an API for a game that can (for now) only be played over Postman issuing POST and GET requests. It needs to be able to receive POST requests and update the InMemory database based on previous requests. Player state is not an issue - it just needs to allow for a player to issue a request and update a value based on the value of the previous request.
I have a Model that contains the class variables and automatically sets one of the variables to a PlayerScore value (0, initially).
public class Game
{
public long Id { get; set; }
public long PlayerScore { get; set; }
public bool Roll { get; set; }
public bool IsComplete { get; set; }
public Game()
{
this.PlayerScore = 0;
}
}
This sets the score to 0 every time the game is played/HTTP POST requests are submitted, but I want to be able to edit this value based on previous turns in the game.
Where should I place this method?
The POST is performed via an 'ActionResult' style method.
Thanks for any help anyone can possibly provide!
You seem to be using your Game class for both your internal game state and also the model from the POST request.
I'd recommend creating a separate class for your POST request so that they don't get confused. e.g.
public class GameUpdateRequest
{
public long Id { get; set; }
public long PlayerScore { get; set; }
public bool Roll { get; set; }
public bool IsComplete { get; set; }
}
// .. controller action
[HttpPost]
public IActionResult UpdateGame([FromBody] GameUpdateRequest request)
{
if (request.PlayerScore > 0)
// update game state logic
}
Then your request model can change and is not tied to the game state model. You could make PlayerScore nullable in the request or add other properties.
Suppose I have the following example Resource Model defined for API Create/Read/Update/Delete interactions involving the Customer types:
public class CustomerModel
{
public string Address { get; set; }
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Url]
public Uri Website { get; set; }
public DateTimeOffset WhenCreated { get; set; }
public DateTimeOffset WhenUpdated { get; set; }
}
Id, WhenCreated, and WhenUpdated are metadata to be generated by the underlying data repository and as such, if the customer adds them to a request they should not be kept (Id for example, would be specified in the URL so no need to include in the request body). However, these values are still important to the client.
Is there a simple approach to ignoring these metadata attributes if sent in the client request? I would expect this in the form of an attribute but have not found anything promising for .NET Core 3.1.
The JsonIgnore attribute would make sense but it wouldn't serialize the values in responses either.
I could create a separate model only used by clients for requests but this seems redundant, especially because it will require new mapping profiles. However, if using something like Swashbuckle for API documentation this could be the best approach since the class documentation wouldn't represent those as valid properties for requests.
I could add some logic to remove those properties in the business logic layer but that would likely involve another request to the database to retrieve their original values so it isn't ideal.
Thank you!
From what I understand. Every time a webapi request goes to the server then it's authenticated. My application uses WebAPI 2, Identity 2 and has get methods such as this:
/api/cityStatusList
/api/cityTypeList
/api/cityOptionList
These calls exist to get data for a page.
If the webapi is authenticating every request then should I look into how I can combine all these requests into one?
If the webapi is authenticating every request then should I look into how I can combine all these requests into one?
Why, is it causing any trouble?
You can of course define and return a class like this:
public class CityData
{
public List<CityStatus> StatusList { get; set; }
public List<CityType> TypeList { get; set; }
public List<CityOption> OptionList { get; set; }
}
Create CityView model class for your city like following :
public class CityView
{
public List<cityStatusView> cityStatusList { get; set; }
public List<cityTypeView> cityTypeList { get; set; }
public List<cityOptionView> cityOptionList { get; set; }
}
public class cityStatusView
{
public int ID { get; set; }
}
public class cityTypeView
{
public int ID { get; set; }
}
public class cityOptionView
{
public int ID { get; set; }
}
use it like following code in your web api :
// View model
var cityStatusList=..;
var cityTypeList=..;
var cityOptionList=..;
CityView objVM = new CityView();
objVM.cityStatusList = cityStatusList;
objVM.cityTypeList = cityTypeList;
objVM.cityOptionList = cityOptionList;
return ActionContext.Request.CreateResponse(HttpStatusCode.OK, objVM);
To address the question directly - yes, it is authenticating your application every time. However, on the scale of standard web-application this time is don't-you-even-worry-about-it miniscule.
Combining those routes into one might well be a good idea not because authentication has to happen multiple times, but because a web request can simply take a while. Typically this is due to the time it takes to physically send signals from the server to the client over TCP/IP (and re-send to compensate for any dropped packets). Even when parallelizing requests, fewer web requests is faster.
That being said, by default I would do the simplest thing possible and not worry about it. What I just mentioned is an optimization, should be treated as such, and not done prematurely.
As for authentication? It's just a few steps of the super-marathon that is your web request, it really doesn't matter. Someone correct me if I'm wrong, but I don't think it usually even hits the database - all it has to do is decode the claims that are stored in a cryptographically-secure fashion in the authentication cookie.
Part of my project is to persist data from another source. In this case we have an SAP data source that we will need to pull data from. I need to take the data from SAP and map it to entities I have in my application. Here is an example of an entity I have in my application:
public class Project : BaseEntity
{
public string Name { get; set; }
public string ProjectNumber { get; set; }
public string Description { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public string Currency { get; set; }
#region Navigation Properties
public virtual Address Address { get; set; }
public virtual CompanyCode CompanyCode { get; set; }
public virtual ICollection<Contact> TeamMembers { get; set; }
#endregion
}
As you can see, I have child objects that I map from SAP as well. I need some advice on the best way to insert and update my entities. I am struggling with knowing when to add (insert) entities to my context and when to attach (update) them, because SAP doesn't have knowledge of what my application may or may not have. I need to guard against duplicates, too. For example, should I perform a lookup of each child entity in my parent entity to see if they exist before I apply them to the parent? Then, add / attach the entire parent object to the context or handle each entity separately while still maintaing their relationships?
Yes you must manually test everything to make correct decision what must be inserted, updated or deleted. Depending on the application you can use some more complex queries to reduce number of round trips to the database - for example you can use single query with Contains to load all TeamMembers needed for processed Project or you can load Project with including all related data if you also need to test if project exists.
I did large synchronization application before and I end up with pre-loading all entities at the beginning with few queries and working completely in memory.
Don't forget to use DbSet's Local property or Find method to take advantage of already loaded entities.
You can also use some custom stored procedures to improve performance of this operation.
What’s Automapper for?
How will it help me with my domain and controller layers (asp.net mvc)?
Maybe an example will help here...
Let's say you have a nicely-normalized database schema like this:
Orders (OrderID, CustomerID, OrderDate)
Customers (CustomerID, Name)
OrderDetails (OrderDetID, OrderID, ProductID, Qty)
Products (ProductID, ProductName, UnitPrice)
And let's say you're using a nice O/R mapper that hands you back a well-organized domain model:
OrderDetail
+--ID
+--Order
|--+--Date
|--+--Customer
|-----+--ID
|-----+--Name
+--Product
|--+--ID
|--+--Name
|--+--UnitPrice
+--Qty
Now you're given a requirement to display everything that's been ordered in the last month. You want to bind this to a flat grid, so you dutifully write a flat class to bind:
public class OrderDetailDto
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public int OrderCustomerID { get; set; }
public string OrderCustomerName { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
public Decimal ProductUnitPrice { get; set; }
public int Qty { get; set; }
public Decimal TotalPrice
{
get { return ProductUnitPrice * Qty; }
}
}
That was pretty painless so far, but what now? How do we turn a bunch of OrderDetails into a bunch of OrderDetailDtos for data binding?
You might put a constructor on OrderDto that takes an OrderDetail, and write a big mess of mapping code. Or you might have a static conversion class somewhere. Or, you could use AutoMapper, and write this instead:
Mapper.CreateMap<OrderDetail, OrderDetailDto>();
OrderDetailDto[] items =
Mapper.Map<OrderDetail[], OrderDetailDto[]>(orderDetails);
GridView1.DataSource = items;
There. We've just taken what would otherwise have been a disgusting mess of pointless mapping code and reduced it into three lines (really just two for the actual mapping).
Does that help explain the purpose?
If you have an object of one type and you want to populate the properties of an object of another type using properties from the first type, you have two choices:
Manually write code to do such a mapping.
Use a tool that will automatically handle this for you.
AutoMapper is an example of 2.
The most common use is to flatten models into a data transfer objects (or, in general, mapping across layer boundaries). What's very nice about AutoMapper is that for common scenarios you don't have to do any configuring (convention over configuration).
Map objects between layers. Good example: Here