Let's say I have this class defined:
public class Animal
{
public int RegId {get;set;}
public string Name {get;set;}
}
And I need to expose it to an remote part of my system ( a client app in another location, for example ) and I decided to use OpenAPI to make the communication.
The controller code is something like:
[HttpGet("GetLivingCargo")]
public async Task<IEnumerable<Animal>> GetLivingCargo()
{
return await pFacade.GetLivingCargo();
}
Swagger generates the documentation all well.
When I generate the API client to use in the remote app, all times I have that class duplicated (so there's my original class and the generated client's exactly equal class).
How I can avoid it, without having to manually write the API client myself to use my original class?
Finally I found a way to make NSwagStudio reuse my Model classes.
Step-by-Step:
Get the OpenAPI spec URL
Make it create an local copy to double check if is the correct spec
Mark "C# Client" on Outputs section of the screen (cannot put an image now because the firewall blocks ImgUr.com)
On Settings tab, two configuration need to be changed:
Additional Namespace Usages: put the namespace list of the classes you want to reuse (comma-separated)
Generate DTO Types: UNCHECK
Generate.
For those who do not want an all-or-nothing approach, with Generate DTO Types checked, you can exclude certain types by filling the (comma-separated) list of types to be excluded in Exclude Type Names configuration setting.
Related
Say I have a controller CatController with actions for GET, POST and PUT. They all use the same Cat resource which could look like this:
public class CatDto {
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool IsFriendly {get; set; }
}
However, the Name and IsFriendly properties should only be required when creating a new cat (POST), but optional when updating it (PUT) to allow updating only a single property.
The way I've handled this until now is simply having two classes, a CreateCat and UpdateCat which have the same properties but different data annotations. However I don't want to have to maintain two almost identical classes.
I could of course validate the model manually in each action, but data annotations are very useful for things like global model validators and automatic generation of Swagger schemas.
I'm also using the Swagger schema to automatically generate SDK's (using ApiMatic), and that results in having two duplicate classes generated (CreateCat and UpdateCat) for what really should only be a single resource (Cat).
Is there an alternative way to achieve what I'm trying to do with only a single class?
I prefer to keep separate models to be honest.
You could have a base abstract ( or not ) model with all the common properties although this is not required and simply adds a third class. Is there a need for it? I'd say no.
There are slight differences between POST and PUT.Neither POST nor PUT require the Id property if you already have that in the PUT endpoint. This negates the need of checking if that Id in URL matches the Id in the model.
Your example does not make the difference visible, but in many cases there are fields you don't really want to update. For example let's say you have a Created and Updated date fields, you would not want to change your Created date via a PUT for example. The more data you have that you do not want to update via a PUT, the more obvious and worthwhile the differences between the models become.
In your case even with those 2 properties I would still create 2 different models, even if they are virtually the same, this sets the expectation on how the API works and creates a clear design in the mind of everyone else who is working on it.
I would recommend against the design you are asking for. According to RFC [RFC7231] you can find here it is advised not to have partial content update in PUT methods.
"An origin server that allows PUT on a given target resource MUST send
a 400 (Bad Request) response to a PUT request that contains a
Content-Range header field (Section 4.2 of [RFC7233]), since the
payload is likely to be partial content that has been mistakenly PUT
as a full representation. Partial content updates are possible by
targeting a separately identified resource with state that overlaps a
portion of the larger resource, or by using a different method that
has been specifically defined for partial updates (for example, the
PATCH method defined in [RFC5789])."
The preferred solution is to use PATCH method instead of PUT. Patch method is described in the RFC in the this link. PATCH method were introduced for partial resource modifications
So look up PATCH methods or if you want to use PUT maybe have a separate endpoint that only takes one of the two values.
More information about PATCH method can be found here
So either go for a PATCH method or create different models and end point to cater for partial update using PUT.
Say I have a controller CatController with actions for GET, POST and PUT. They all use the same Cat resource which could look like this:
public class CatDto {
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool IsFriendly {get; set; }
}
However, the Name and IsFriendly properties should only be required when creating a new cat (POST), but optional when updating it (PUT) to allow updating only a single property.
The way I've handled this until now is simply having two classes, a CreateCat and UpdateCat which have the same properties but different data annotations. However I don't want to have to maintain two almost identical classes.
I could of course validate the model manually in each action, but data annotations are very useful for things like global model validators and automatic generation of Swagger schemas.
I'm also using the Swagger schema to automatically generate SDK's (using ApiMatic), and that results in having two duplicate classes generated (CreateCat and UpdateCat) for what really should only be a single resource (Cat).
Is there an alternative way to achieve what I'm trying to do with only a single class?
I prefer to keep separate models to be honest.
You could have a base abstract ( or not ) model with all the common properties although this is not required and simply adds a third class. Is there a need for it? I'd say no.
There are slight differences between POST and PUT.Neither POST nor PUT require the Id property if you already have that in the PUT endpoint. This negates the need of checking if that Id in URL matches the Id in the model.
Your example does not make the difference visible, but in many cases there are fields you don't really want to update. For example let's say you have a Created and Updated date fields, you would not want to change your Created date via a PUT for example. The more data you have that you do not want to update via a PUT, the more obvious and worthwhile the differences between the models become.
In your case even with those 2 properties I would still create 2 different models, even if they are virtually the same, this sets the expectation on how the API works and creates a clear design in the mind of everyone else who is working on it.
I would recommend against the design you are asking for. According to RFC [RFC7231] you can find here it is advised not to have partial content update in PUT methods.
"An origin server that allows PUT on a given target resource MUST send
a 400 (Bad Request) response to a PUT request that contains a
Content-Range header field (Section 4.2 of [RFC7233]), since the
payload is likely to be partial content that has been mistakenly PUT
as a full representation. Partial content updates are possible by
targeting a separately identified resource with state that overlaps a
portion of the larger resource, or by using a different method that
has been specifically defined for partial updates (for example, the
PATCH method defined in [RFC5789])."
The preferred solution is to use PATCH method instead of PUT. Patch method is described in the RFC in the this link. PATCH method were introduced for partial resource modifications
So look up PATCH methods or if you want to use PUT maybe have a separate endpoint that only takes one of the two values.
More information about PATCH method can be found here
So either go for a PATCH method or create different models and end point to cater for partial update using PUT.
I can use the .Net ConfigurationManager to store strings, but how can I store structured data?
For example, I can do this:
conf = ConfigurationManager.OpenExeConfiguration(...)
string s = "myval";
conf.AppSettings.Settings["mykey"].Value = s;
conf.Save(ConfigurationSaveMode.Modified);
And I would like to do this:
class myclass {
public string s;
int i;
... more elements
};
myclass c = new myclass(); c.s = "mystring"; c.i = 1234; ...
conf.AppSettings.Settings["mykey"] = cc;
conf.Save(ConfigurationSaveMode.Modified);
How do I store and retrieve structured data with the ConfigurationManager?
I implemented a solution as #sll suggested. But then difficulty was to create a new section to the configuration. Here is how this is done:
How to Write to a User.Config file through ConfigurationManager?
You can create own configuration section type by inheriting from ConfigurationSection class and use it to save/load any custom type information.
MSDN: How to: Create Custom Configuration Sections Using ConfigurationSection
BTW, One advice which might be helpful for you or others: One good thing is making custom configurations section class immutable (no public setters) so you can be sure that configuration cannot be changed on any stage of application life cycle, but then if you decide writing unit tests for code which relies on configuration section class and need section stub with some test values you might stuck with abilty to set property values since there is no setters. Solution is providing a new class which is inherited from your section class and specifying in constructor values using protected indexer like show below:
public class TestSectionClass: MyConfigurationSection
{
public TestSectionClass(string testUserName)
{
this["userName"] = testUserName;
}
}
Serialization.
There are numerous different ways of serializing data, so you'd need to pick one. But .NET provides a serialization API that suits a great many cases, and in working with web AJAX calls recently I find myself using JavaScriptSerializer heavily to turn things into JSON. However there are third party libraries such as protobuf-net, and so on.
The key here is to essentially turn your data into a byte or string representation that can later be deserialized back to its original structure at a later date, allowing you to store it in a medium between then, such as in configuration files or transmission over networks etc.
As per #sll's answer, .NET has another facet meaning it can handle serialization of data in and out of custom configuration sections; whether you want to begin specifying types explicitly for this purpose or not is your call. Bottom line is the same, serialize, somehow.
I have a edmx model created from a database and a metadata.cs for it.
In the client, the .g.cs includes [StringLength(X)] attributes alongside my attributes from my metadata.
I am doing some serverside validation for a flat file import that is seperate to the client side editors of these entities.
I am able to apply my range and regular expression validations but I am unable to find the StringLength attribute on the server. Does anyone know how to do this without duplicating the StringLength attributes manually on the metadata properties.
Edit:
Here is some code:
Server side file ProductService.metadata.cs:
internal sealed class PRODUCTMetadata
{
[Required]
[RegularExpression("[A-Z]+")]
[Display(Name = "Product Code", Order = 10)]
public string Product_code { get; set; }
}
Client side Generated_Code\NameSpace.Web.g.cs:
public sealed class PRODUCT
{
[DataMember()]
[Display(Name="Product Code", Order=10)]
[RegularExpression("[A-Z]+")]
[Required()]
[StringLength(8)] //This is what I want to know, but server side
public string Product_code
{...etc
}
}
I've investigated a bit around this problem, and couldn't find any good information about the topic on the Internet. So what' I'll say here is only assumption.
As you have seen, the auto-generated client proxy code is much more decorated with attributes than the server-side code. Your entities for instance have the nice [StringLength(8)] attribute that comes from the Entity Model. On the server side, the auto-generated .metadata.cs file doesn't have those attributes on entities. I think it's all about code-generation templates.
I suspect that the code generation template of RIA Services (that creates the .g.cs file) is much more complete than the template that creates the .metadata.cs file on server side.
The fact that the attribute that is missing in your case is 95% of time used for UI validation on client-side might explain why the template for the .metadata.cs file doesn't produce those validation attributes.
I see 2 work-arounds for your problem:
1. Write your own metadata class on server side
Some example:
[MetadataTypeAttribute(typeof(PRODUCT.PRODUCTMetadata))]
public partial class PRODUCT
{
internal sealed class PRODUCTMetadata
{
// Metadata classes are not meant to be instantiated.
private PRODUCTMetadata()
{
}
[StringLength(8)]
public string Product_code { get; set; }
}
}
You can manually add any attributes to the properties of your entities, as entities are partial classes.
Unfortunately, you'll have to maintain those metadatas each time you modify your model: if (for example), your DB table column changes from varchar(8) to varchar(10), you'll be able to automatically update your EDMX model from your database, but you'll have to manually check that your metadatas are still OK (in this example, you would have to manually replace [StringLength(8)] by [StringLength(9)]).
Here's a nice link about metadata.
2. Modify the T4 templates
Second option is probably the best one, but I didn't experienced myself the code generation template modification, so I don't known what can effectively be done or not.
Code generation templates are known as T4 templates (Text Template Transformation Toolkit). It is possible to modify those templates to include anything you want in the code generation process. You could modify the default EF template so it generates the missing attributes just as the RIA Services template does.
Here's some nice articles about T4 code generation:
http://www.scip.be/index.php?Page=ArticlesNET36#T4CodeGenerationClasses
http://msdn.microsoft.com/en-us/data/gg558520
http://msdn.microsoft.com/en-us/library/cc982041.aspx
I write this as an answer (it wouldn't fit as a comment), but remember it's all assumptions.
Our system complexity has risen to the point that we need to make permission names tied to the client from the database more specific. In the client, permissions are referenced from a static class since a lot of client functionality is dependent on the permissions each user has and the roles have a ton of variety. I've referenced this post as an example, but I'm looking for a more specific use case. Take for instance this reference, where PermissionAlpha would be a const string:
return HasPermission(PermissionNames.PermissionAlpha);
Which is great, except now that things are growing more complex the classes are being structured like this:
public static class PermissionNames
{
public static class PermissionAlpha
{
public const string SubPermission = "PermissionAlpha.SubPermission";
}
}
I'm trying to find an easy way to reference PermissionAlpha in this new setup that will act similar to the first declaration above. Would the only way to do this be to resort to pulling the value of the class name like in the example below? I'm trying to keep all the names in one place that can be reference anywhere in the application.
public static class PermissionAlpha
{
public static string Name { get { return typeof(PermissionAlpha).Name; } }
}
** Edit ** - Added missing permission name.
Maybe this would be too big of a change for you with the size of your project, but we have all of our business objects split into partial classes. One is for manual changes and one gets generated. During code-generation, we write the permission keys into the generated side of the partial classes from our "single source of truth". We're using a set of classes as our source of truth and CodeDom to generate, but you could also use a database as your source and use T4, CodeSmith, or others to generate.
Why not create reflectable attribute(s) on the classes in question? That way one can add all the extra information required. I provide a way of divining attributes on my blog article entitled:
C# Using Extended Attribute Information on Objects
HTH