Name Collissions on DTOs

I get that. But I’d go farther and say it’s fundamental to how ServiceStack exposes it’s APIs, and not necessarily how they’re built. If I built a standard route-based API and exposed it through OpenAPI, there are tons of libraries that would auto-generate a client for me. It likely does some auto-naming or conventions-based namings of the classes it generates. If it has a conflict, during generation it appends a 1 or 2 or 3… That’s fragile, I get it. Next time you generate, what was suffix 1 might now be suffix 2 given the addition of some class.

What about this… instead of requiring unique names during my DTO/service vreation, can I do that through configuration?

ServiceModels.InAssembly(…).AddPrefix(“…”); That way my developers are free to develop within their domain, and it’s on me, the one bringing all these separate domains together, to add configuration that guarantees uniqueness?

InAssembly(typeof(Assembly1.MyThing).Assembly).AddPrefix(“Assembly1”)
InAssembly(typeof(Assembly2.MyThing).Assembly).AddPrefix(“Assembly2”)

/ui/Assembly1MyThing
/ui/Assembly2MyThing

In my service model assemblies,

public class Assembly1.MyThing : Assembly1.DtoBase { }
public class Assembly2.MyThing : Assembly2.DtoBas { }

In the code generation,

public partial class Assembly1MyThing : Assembly1DtoBase { }
public partial class Assembly1DtoBase { }

public partial class Assembly2MyThing : Assembly2DtoBase { }
public partial class Assembly2DtoBase { }

That seems like a good concession to not not breaking SS fundamental concepts while still allowing for use cases like mine.

.NET languages are the one place which does support types in different namespaces if you don’t override the default namespaces.

It’s still going to break in every other language.

Can you look again at my suggestion? I didn’t add multiple namespaces. I used a prefix so there wouldn’t be collisions when generating the code, and also when generating the auto-routes such as /api/{dto} and /ui/{dto}.

Doesn’t that solve both our concerns?

I’m saying C# doesn’t need this workaround, it already supports types in different namespaces. Are you suggesting I change every other language to support this feature?

What’s with these weird hacks, why don’t you just change the conflicting type names?

This is a feature that no-one else is going to use.

Definitely not suggesting that, no!

Let’s take a step back. The issue I’m facing is that I have two domains: Users and Widgets.

In Users, I have a GetAccount { int UserId; } service model at route /users/{UIserId}/account that returns an AccountResponse { public int Id; public string Name; }

In Widgets, I have GetAccount { int WidgetId; } service model at /widgets/{WidgetId}/account that returns AccountResponse { public int Id; public int WidgetCount; }

From a DDD standpoint, each have their own idea of what an Account is. So they have individual AccountResponses. And from a DDD perspective, they both are calling GetAccount.

This presents a problem in the SS admin if I want to host both of these in the same service. Because /ui/GetAccount and /api/GetAccount won’t know which version to present.

Similarly, whatever does load in the UI ends up being a composite of the two. So when I load /ui/GetAccount it generates an autoform with UserId and WidgetId as the two request properties on the screen. Instead of picking one or the other, it’s picking both and merging them. I can only assume because it’s creating an internal dictionary and adding in the properties from the type. You can see this most notably when when you use the C# code generator. It uses partial classes everywhere, so you can clearly see why it would end up with both properties in the GetAccount DTO.

So how do we fix it? I can go to all my teams and say “sorry, but someone already used GetAccount. Please rename your class. Oh and also the AccountResponse name is also taken. So rename that too. Oh and the UserType enum. Yea… rename that, too.” That’s a lot to ask the team to rename.

What I’m suggesting is saying “In typeof(UserService).Assembly, when generating code, prefix all objects with ‘User’; and in typeof(WidgetService).Assembly, when generating code, prefix all objects with ‘Widget’”

The end result is /ui/UserGetAccount and /ui/WidgetGetAccount as the auto-generated code. It’s a collission-prevention mechanism. I don’t see how I’d be the only one to use this and how this wouldn’t be a useful feature.

My only other solution right now would be to deploy this as a series of microservices so that I have literally different sets of APIs on different deployments. I’m trying to avoid that. I’m trying to use a modular monolith approach here. Having some kind of mechanism to work around the unique-name across all services requirement would solve for that while keeping the fundamental requirement of uniqueness intact.

We’re misaligned on the meaning here. Either I’m missing the point you’re making or you’re missing the point of my suggestion. If it’s me, let me know where I’m off on my assumptions. Thanks.

Either get them to rename conflicting types or map the types in the Service implementation to a non-conflicting DTO and return that so your internal conflicts are not projected beyond your service layer.

Or fix the root of the problem of having independent teams and have isolated AppHost/APIs per team. The main value of microservices is to enable teams to work freely so they can avoid conflicts like this.

I don’t think it would be useful because I don’t know of anyone else having this issue where they return duplicate types like Account and they leave it up to the client to workout why their different. Do you know of any public API that does this?

I just don’t understand why you think I’m leaving it up to the client to work out. I’m asking AppHost, not the client, to allow me to stitch together my service services. The same way SS allows me to configure what metadata it generates. The same way I can add to my service model VisibleTo settings so SS knows whether or not to generate that particular class when it does generate client libraries. If SS on the AppHost side simply changed what it auto-generates for the user in all clients then it would be as if the developers had named those objects that way in the first place. I honestly see no difference.

The thing about public RESTful APIs is that the underlying implementation should be client agnostic.

If I used MVC-based APIs, it wouldn’t care if I used the same class name (in different namespaces). This requirement of complete uniqueness across all servicemodel assemblies feels like it’s bleeding implementation requirements into my service layer. This isn’t the first time I’ve had this issue, and I’ve worked around it in the past by simply renaming DTOs. I’m looking for ways to avoid having to do that while still not changing a fundamental requirement of SS.

What does their generated APIs look like? How many languages do they support this in?

Agreed, you’re already free to call these APIs with duplicate type names from a REST API, use a generic HTTP client and parse the untyped JSON. The issue is generating conflicting types in different languages.

That doesn’t change any of the questions I’m asking, nor does it change that you think I’m asking the client to do something. I get it. It’s why I’ve used SS for every project I’ve worked on since it first launched. This one issue has been a thorn in my side a few times. I’m proposing a solution that continues to allow that fundamental requirement without imposing the requirement at development time. By allowing me, the AppHost creator, the guy gluing everything together and standing up my service, to apply a prefix/suffix to the service models being referenced in my service assemblies, I can universally stitch together whatever services I want regardless of service source. It becomes infinitely composable by allowing me, the AppHost creator, to define how the composition will work.

I know it’s not recommended, but the same solution could be applied to a V1 vs V2 service assemblies. All sevices in (MyApp.V1.UserService) I would prepend a V1 to the name; and all services in MyApp.V2.UserService I would prepend a V2. So V1GetUser and V2GetUser. They already have different [Route] attributes. But they can’t co-exist under the same deployment simply because they have the same DTO name. Right? So if we added metadata to the “What is my DTO name?” question and the answer is $“{Prefix?}{DTO}” then does that not retain the integrity with allowing stronger composition without requiring design-time requierments of uniqueness?

No one’s going to use this feature because their just going to change the type name instead of resorting to ugly workarounds like this. This feature basically generates incompatible types so now client source code that uses this is incompatible with code from other clients or the internal service gateway implementations that use real types.

I’m not considering this feature because it’s highly disruptive, goes against the constraints existing features were designed with, adds complexity to the code-base trying to support a feature I dislike that we have to maintain and support forever and factor in our future features that this affects, that no-one else will use.

As such I don’t want to have it in ServiceStack’s code-base. If you want to support this feature yourself you’re free to take a copy of the Add ServiceStack Reference implementation for the language you want, e.g. for for C# it’s in CSharpGenerator.cs which is called from TypesCSharp API and create a different API with a modified copy that suits your usecase.

I’m fine with you not wanting to add it to the codebase. I’m still really bothered that you think this is one-off client generation thing. If I felt that we were seeing eye-to-eye on the feature and still you didn’t want to add it, then I’d have let it drop ages ago. Give your last message, I still think what you think my ask is doesn’t align with what I’m actually suggesting to add, nor would it generate incompatible types or any of that.

Regardless, I’ll drop it now. I just wanted to add this last comment for future search sake in case someone else has the question.

I appreciate your time, mythz. Thank you

1 Like

For the record, this is not true. I was asking for this awhile back, and you gave me the same uninspiring response. Typescript-ref and similar class names, different namescape - Clients / TypeScript - ServiceStack Customer Forums

My use case is simple and similar. We have a bunch of Features we want to plug into a single API project. Each feature has its own service models / interfaces, and while running 1 API per 1 Feature separately they are fine, when running multiple features in a single API they can run into the same conflicts described above.

It would be awesome if you could produce a logical work-around that fixes this issue we are experiencing-- to have a way to plug in multiple features and service stack take care of ensuring that each service model/interface is auto-mapped to ensure no duplication of type names.

Thus allowing the metadata / openapi / auto-gen service clients dtos to all get wired up correctly so that when using the serviceclient’s / dtos it hits the API and routes to the correct feature’s service implantation.

It could be as simple as adding the feature name to the pattern and ensuring the mappings get wired up, and as @grexican pointed out, can be optional configuration to wire it up.

 appHost.LoadPlugin(new SomeFeature()).WithPrefix(nameof(SomeFeature));
 appHost.LoadPlugin(new SomeFeature()).WithDefaultPrefix();

Then when generating the dtos / metadata code Account would become SomeFeatureAccount. It’s url would be prefixed with /SomeFeature/ and it allows for the dev teams to work without needing to be aware of this current limitation.

I hope you reconsider your opiniated position, as there are valid use cases out here and your current position leaves a gap in your product. You don’t see it, but it’s there and now I know I’m not the only one to come across it. A lot of friction that could be reduced if only you saw the value in doing so-- even if it was just for this use case.

Thank-you for your time and attention to this matter.

1 Like

Yep, you get it, Charles. To the generated code’s perspective, it would be as if the end users wrote the plugin with the prefix themselves thus avoiding any collisions without putting the burden on the individual plugin codebase owners.

1 Like

I’m finding myself struggling with a similar problem. I’ve got a lot of experience in the Django framework, where “projects” are structured as a set of “applications”, (Applications | Django documentation | Django) and the framework provides functionality to assign all the stuff in an application, like all of its Routes, etc, under a prefix, which is why it feels similar to your issue… Most things have an adaptation to deal with potential conflicts in naming as the “application” abstraction allows you to just pull in a package from the public registry “PyPI” and use it as an “re-usable application”, where you have no control over database model names and class naming. For instance the Django framework has a built in authentication component which is an application with its own models, admin interface setup etc, and you can pull it in to a project simply by adding "‘django.contrib.auth’ to the “INSTALLED_APPS” setting, and other applications such as the built in admin can reference it via the normal Python code mechanisms to ensure the built in admin is only visible to logged in users.

While I’m not struggling with duplicate DTO naming, I am struggling with app structure, because I’m so much more used to being able to structure my websites/services “projects” as a set of “applications” which are combined together at the root of the “project”. ServiceStack is a great framework, but the standard project structure where it gives me 4 boxes “<project>”, “<project>.ServiceInterface”, “<project>.ServiceModel”, and “<project>.Tests” and everything lives inside these big flat namespaces with no ability to logically group together. Based on the docs I have a feeling that “plugins” is potentially a solution to my problem, but there isn’t a lot of examples for using plugins to group services, there’s one short section in the docs, and the auth service, but these don’t really show how you would take most of the functionality of a complete project (modulo what can’t or shouldn’t be in the plugin) and put it inside a plugin, and then add that plugin to a “parent” ServiceStack “project”.

This kind of composition of components feels very related to the issues your having @grexican and @Charles.

@mythz do you think there is a way to leverage the plugin mechanism to control the merge/translation of these DTOs into the unified top level project namespace, the level at which the DTOs need to have unique names in order to not break other language clients? I’m asking directly because I’m used to having these kind of mechanisms with what I think are equivalent features and I’m still pretty new to using the more advanced parts of ServiceStack, like writing my own Plugins.

Slight derail… I’m honestly not sure I fully understand plugins other than their primary use, which from the publicly available code I have to read for examples, appears to be for dropping in “logical” features like the AutoQuery system, or request logging, etc. Other than having the example of the Auth service as a “counter example”, I’m genuinely unsure that plugins are meant to be used to encapsulate a complete set of classes, DTOs, app logic, DTO to database mappings, and everything else that would be spread out across the “<project>”, “<project>.ServiceInterface”, “<project>.ServiceModel”, and “<project>.Tests” folders/assemblies. If there are examples I’ve missed that show how to take a top level “project” (with DTOs, logic, database mappings, etc) and turn it into a “plugin” and then include that plugin into a “parent” project all in the one codebase, I’d love to be pointed to it since I’m still trying to fully understand some of these ServiceStack of internals.

Plugins can indeed encapsulate functionality like services, filters, validation etc. The recommended pattern in the templates of ServiceModel/ServiceInterfaces/AppHost/Tests is there to strike a balance between basic setup vs one that will scale pretty well for a lot of use cases without the need to add additional projects, but that doesn’t mean you need to fit ‘everything’ in those 4 projects for any size application.

You start with these 4 boxes, but as your application grows, you might then start breaking up into additional ServiceModel/ServiceInterface/Tests projects depending on your requirements. This actually maps pretty well to what you describe where your ‘application’ is your AppHost, the entry point, that can use a combination of ServiceModels/ServiceInterface projects, however one difference might be, AppHosts are what you run and what listens for HTTP requests. We have a quick video tutorial that might help with this here →

If you are finding it hard to manage all your services in one AppHost, you might want to consider breaking them up into logical ServiceModel/ServiceInterface projects, however the constraint of uniquely named RequestDTOs still exists for each hosted AppHost. This same constraint also exists for any services added via Plugins. A Plugin can add the Services, how the Request DTOs still need to be unique within the AppHost. How those features are registered can be a bit different compared to working with your AppHost directly, the different life cycle interfaces sometimes need to be used to make your plugin register what it needs at different stages.

Plugins aren’t meant to wrap up entire applications/projects, but rather make individual features more composable. This can help especially for when you might have multiple AppHost projects.

I really appreciate your feedback on your journey coming from Django and learning ServiceStack, it helps us develop better documentation/tutorials. We are missing a longer concrete walkthrough of the development of custom Plugins, so this is something we’ll look at creating additional learning resources for, to make it easier to understand and leverage. If you feel there are any other gaps let us know, and I can either point you in the right direction or also look at how other docs and tutorials can be improved.

1 Like

As Darren mentioned plugins are for wrapping composable functionality which works for encapsulating any features, functionality, embedded resources and services a specific feature needs, but they’re not intended for splitting up your Application.

The recommendation is that all your DTOs are in your ServiceModel project which defines your typed Services contract. I go into explaining the importance of DTOs in the Complexity, Services and Role of DTOs docs. A DTO is a canonical symbol for a structure that your Service exports which is important that it’s unique. You can have multiple duplicate type names and that will serialize fine like it does in any Web Services framework but to support code generation in non .NET languages they need to be unique.

Smaller to medium sized projects should typically not need more than a single ServiceInterface assembly for your Services implementation. For larger projects I would refactor out the implementation of Services into a ProjectName.Logic assembly like EventMan.Logic that the Physical Project Structure docs mentions.

Whilst for even largest projects the Modularizing Services docs shows an example of how you can split your Services implementation across multiple assemblies, e.g:

public class AppHost : AppHostBase
{
    //Tell ServiceStack the name of your app and which assemblies to scan for services
    public AppHost() : base("Hello ServiceStack!", 
       typeof(ServicesFromDll1).Assembly,
       typeof(ServicesFromDll2).Assembly
       /*, etc */) {}

    public override void Configure(Container container) {}
}

This should be able to handle splitting out even the largest of projects, if you need even more modularization than you should start thinking about Microservices to split out cluster of functionality into different AppHosts which the Service Gateway can help with for any inter service calls.

Thanks for the helpful replies @layoric and @mythz

This was the impression I was left with from the documentation. The plugin feature is more about being able to “bolt on” mostly self contained functionality that you want to encapsulate and separate out, be it as a separate csproj in the same solution or a fully separated nuget package. They are primarily designed to “plug in and add on” their functionality, not as a generic “sub-component” complexity management mechanism.

Thanks. In all honesty documentation has been the biggest part of the learning journey by far. Using C# for several things now for a couple of years (compared to the >10 I have with Python) the language has few pitfalls, and is quite expressive. But the documentation, its wild… there’s excellent patches that clearly show how to do things, often smaller packages, that are fantastically documented, then there are huge swaths of documentation that is basically the .Net equivalent of the exported Java class docs with nicer HTML and CSS that doesn’t make your eyes bleed, there’s mountains of “just install our VS addon/plugin and use it to generate this based on these convenient class annotations” with zero other documentation on how to manually code anything and maybe some API docs on how the generated code can be used, and I seem to have picked a terrible time to learn a new skill as the wider educational market has drifted to monetised YouTube videos and self hosted course platforms instead of books and blog posts, and stack overflow is full of very old dotNet and C# content from back in the Foundation only days when it was a windows only world.

The ServiceStack docs are among the best I have found in the .Net world! But as a user of the framework I do find them a bit lacking compared to the documentation of Flask or Django in the Python world. Where there is a thorough onboarding section to introduce all (or at least the most common 80%) of the framework’s features and explain any framework specific terminology or methodologies to the new user before also including more detailed “how to use” reference and API documentation.

Just to clarify that a bit, your Django “site”/“project”, specifically the “WSGI config” is the HTTP handling entry point that would be most equivalent to the AppHost, and thanks to the extra context you’ve both provided provied in your replies, I now see that there isn’t actually an equivalent in ServiceStack to an application in a “Django app” sense of the word. I can make my own substitute by grouping multiple ServiceModel/ServiceInterface sets together as part of a larger dotNet Solution, but that’s just a difference in code organisation strategy (and it that might be worth adding to the physical layout docs as an example of what comes next as a project grows if there aren’t downsides I’m not aware of yet)… I can have TopLevelProject TopLevelProject.component_one.ServiceModel, TopLevelProject.component_one.ServiceInterface, TopLevelProject.component_two.ServiceModel, TopLevelProject.component_two.ServiceInterface and so on… and so as long as all the project and solution references are configured correctly as far as ServiceStack, C# and dotNet are concerned, it’s all the same to them as if there was just TopLevelProject, TopLevelProject.ServiceModel, and TopLevelProject.ServiceInterface. Nothing has been “modularised”, its just better organised.

To your point here @mythz

makes sense in this light, and also highlights one of the things that I find hard to reason about about based on the current documentation. To me this kind of a refactoring makes sense, if the service has logic spread out and its hard to work with, pull that into its own assembly/module, but adds yet more context to an implicit impression I have of ServiceStack, that its primarily designed for “microservices”/“self contained” services…

The experience I’ve had with Flask and Django in Python, Rails with Ruby, and Phoenix with Erlang/Elixir have involved projects where multiple things are handled by the one codebase… It will have logically grouped sections of functionality for all the things that have been added to the codebase/project because everyone is trying to contain complexity (Complexity, Services and Role of DTOs). Something might begin as an inventory and stock tracking system, then get extended to add warehouse management, then add external logistics for shipment tracking, then regulations change and they have to add a dedicated auditing history functionality, and one manager really wants to be able to plan and track future projects so you end up with some bare bones project management functions… all of this can co-exist neatly inside a Django project, each large enough logical section getting its own Django application, with its own collection of related database models with their specific business logic attached for the CRUD actions being performed on them, each mostly self contained but with relationships to models in other applications as appropriate, common things getting factored into utility applications to keep things DRY, and overall the complexity gets managed… which I don’t have examples of how to do for ServiceStack.

There are a couple of examples that show complete working Code-First projects like GitHub - ServiceStackApps/EmailContacts: Example layout of a typical medium-sized ServiceStack App with Rabbit MQ enabled, GitHub - NetCoreApps/Chinook: AutoQuery APIs around Chinook SQLite DB and GitHub - NetCoreApps/BookingsCrud: Code-first, declarative, multi-user .NET Core Booking system using Auto CRUD & ServiceStack Studio but these are small enough that they would comfortably live in a single Django application, GitHub - ServiceStackApps/Northwind: Northwind Data Servicified with ServiceStack seems like it might be a “two app” Django project if you wanted to keep things more tidy than they currently are but that’s a matter of preference and not being code-first it’s not a good example of how to managing a code first project project, beyond that its sort of left to us the user as an exercise in our best judgment how to fight the complexity as applications grow in scope and keep things organised, as there are no examples (at least that I have found) of what sort of layout would be even notionally better one way or the other.

I have to point out most of this does make more sense to me personally now I’m not confused by mis-understanding the point of the plugin mechanism, and I can see that ServiceStack is sticking to its guns on YAGNI by not building mechanisms that it doesn’t need to do what its trying to do… But since I’m here I’m just taking the opportunity to highlight what feels to me like a shortcoming of the documentation overall to someone with the bulk of my experience coming from outside the C#/.Net ecosystem. Much of my frustration learning anything C# or .Net related are because the framework, the compiler or the IDE will just do something for me, and the documentation doesn’t feel the need to mention these externalities, its been a consistent experience across all the documentation I’ve read for things in the C#/.Net ecosystem, if I’m struggling to understand something, 80% of the time it turns out to be because the documentation has assumed I already know something is going on elsewhere that they never mentioned, (and 80% of that is usually because they didn’t fully explain what Dependency Injection stuff they are expecting so I’ve made a mistake when initially adopting their module)

2 Likes

Thanks for the detailed feedback, also checkout:

For examples of larger projects, but still not large enough to refactor their ServiceInterface into multiple assemblies. It would need to be a fairly large project to require me to want to do add an additional assembly (typically the reasons for adding assemblies is to do with cohesion and dependency requirements rather than size), but my approach would be fairly straight forward, ServiceModel DTOs define your services contract, ServiceInterface is your surface level implementation of the contract and the implementation of those services can invoke different dependencies for their logic which can be refactored as you see fit.