Ignore certain ViewModel properties in API requests? - asp.net

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!

Related

How to design an internal Web Api using ASP.NET Web API

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

Is there much authentication overhead when WebAPI makes a request to the server?

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.

Implementing PATCH in webapi

I have an object that I want to update partially using webapi/json here is an example of my model
public class Location
{
public int Id { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
The JSON from the client will be
{
"Id": 1,
"Address":"new address"
}
The webapi function looks like this
public bool Patch(Location location)
{
//do something
}
Problem is the only field updated was the address so without checking each field for string.isnullorempty I can't tell what has changed and more over null/empty could just mean delete the value is there a more seamless way to do this?
JSON Patch is not natively supported by ASP.NET Web API. There are currently two implementations for the JSON-patch spec that are available for .NET (at least that I'm aware of):
myquay/JsonPatch
Github: https://github.com/myquay/JsonPatch
NuGet: https://www.nuget.org/packages/JsonPatch/1.0.0
KevinDockx/JsonPatch
GitHub: https://github.com/KevinDockx/JsonPatch
NuGet: https://www.nuget.org/packages/Marvin.JsonPatch/0.3.0
Both of these are currently in "alpha" status, and neither of them implement the spec fully yet.
Not really. That's why there is Json-patch however, to my knowledge no-one has written a .net library for it.

Entity Framework 4.1 Code First: Advice on persisting data from external source?

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.

During JSON Serialization in .NET, is there a way to specify how "deep" the object graph you wish to go?

I have some complex object graphs, when I want to send them down to the client, I'm creating a separate DTO and serializing the objects into that. This is a pain in the ass. Is there anyway to serialize objects and only say, "Go one references deep" so if I have an object:
public class Test {
public Project { get; set; }
}
public class Project {
public int Id { get; set; }
public Vendor Vendor { get; set; }
}
If I go to serialize Test it won't go to the Vendor, but it'll correctly serialize the Project. I realize I can add an annotation for JsonIgnore, but if I were serializing all Projects, I might want a Vendor.
I think you're going to have to do some custom extension work: I found a conversation and some samples at http://json.codeplex.com/Thread/View.aspx?ThreadId=24459

Resources