I wanted to bring this up again as a kind of ugly issue. I’ve been dealing with this by naming my service DTOs like
namespace Web.Service.Authentication
{
public class WSAUser : IReturn<WSAUserResponse>
{
}
public class WSAUserResponse
{
}
}
But this just looks bad - and I’m back to square one if I add a new namespace “Web.Status.Animals” with a dto inside called “User” (making the service WSAUser again)
I understand that other languages don’t support namespaces, but wouldn’t it make more sense for the NativeTypes feature to generate types with names which are the full namespace?
So in F# the user dto would be called “WebServiceAuthenticationUser” ?
Sure I could do this myself by renaming the class to
namespace Web.Service.Authentication
{
public class WebServiceAuthenticationUser : IReturn<WebServiceAuthenticationUserResponse>
{
}
}
just looks bad.
I guess the second part of your answer addresses the ugliness bit - but I’m not sure what the proper solution for web service interoperability is? To make each namespace its own web instance?
Nothing’s changed, don’t rely on namespaces in your Service Contracts, it’s extremely fragile and brittle and a source of runtime issues and won’t work in other languages and other generic metadata Services which doesn’t have any concept of namespaces. This isn’t going to change in time, code-level concerns like namespaces don’t belong in Service Contracts, it never will.
Each Type should be unique not only in your Service but in your network boundary so when you publish a Type in a MQ every service in your network should know exactly the type it’s referring to, it should not be limited to .NET clients who needs to rely on out-of-band internal server info like C# namespaces that’s not serialized with the Type.
namespace Web.Service.Authentication
{
public class WebServiceAuthenticationUser : IReturn<WebServiceAuthenticationUserResponse>
{
}
}
```
It wouldn't be so verbose if you didn't prefix your Types in a Web Service with `WebService` or a `Web.Service` namespace, that's not adding any value. The 2 User Type examples above I'd just call `AuthUser` and `AnimalUser`.
Not sure what you’re trying to achieve, a lot of schema-less serialization formats (e.g. JSON, JSV, CSV) does not include the Type name. For serialization formats that do like Xml you can use:
[DataContract(Name = "NewName")]
public class OldName { ... }
But this isn’t going to impact code generation. The purpose of your DTOs is to define your Service contract, the generated names is the Type name which when using typed generated DTO sends the symmetrical type on the client that’s implemented on the server, e.g:
client.Post(new AuthenticateUser { ... });
...
public class MyServices : Service
{
public object Any(AuthenticateUser request) => ...;
}
Other clients calling your Service via HTTP are going to use the custom route, e.g:
[Route("/users/authenticate")]
public class AutenticateUser { ... }
I guess my viewpoint is just biased because I only operate with the http endpoints not any C#/F#/etc clients. In my world the route “/users/authenticate” is literally “AuthenticateUser.” Whatever is posted there becomes AuthenticateUser regardless of what type name the client sent.
As to your question I would expect with a service such as “AuthenticateUser” my ideal code would be
Server:
namespace Authentication
{
[ServiceName("AuthUser")]
public class User {}
public class MyService : Service {
public object Any(User request) {}
}
}
// the DTOs generated from the NativeTypes endpoint would be the "ServiceName" not the namespaced type
client.Post(new AuthUser { ... });
My issue is certainly a small cosmetic thing it just kind of bugs me when I can’t use namespaces in a language that was designed with namespaces.
It especially bothers me with responses since before realizing this I was doing:
namespace Authentication.Services
{
class User : IReturn<Responses.User> {}
}
namespace Authentication.Responses
{
class User {}
}
With the attribute would become
namespace Authentication.Services
{
[ServiceName("AuthUser")]
class User : IReturn<Responses.User> {}
}
namespace Authentication.Responses
{
[ServiceName("AuthUserResponse")]
class User {}
}
(ServiceName is a bad description for what its trying to do but yeah)
Nouns like User are a Type and should not be reused for your Request DTO which is typically a verb to define what your Service does, e.g AuthenticateUser. If your service defines multiple Request DTOs with the same you have an API design problem as your API is confusing to whoever else is trying to consume it.
You can freely use c# namespaces in your service implementation and data models, but your DTOs are your external facing Service contract, this is the contract your server realizes and your external clients bind to, why you’d want your generated DTOs to be different to what the Server implements where clients using your .dlls are incompatible with clients using generated code is beyond me.