I'd like to define an interface on some of my servicestack service model request dto objects. I've defined the interface in my service model project and added it to the dto objects.
But in the client application when I use the "Update Service Stack Reference" function with the Visual Studio plugin, my interface definitions are not being added to my DTOs.
Previously the only interfaces included in the Add ServiceStack Reference feature are existing interfaces defined in the dep-free ServiceStack.Interfaces.dll to reduce coupling with external libraries but support for exporting (non-generic) implemented interfaces were just added from v4.5.13 which is now available on MyGet.
An alternative to having interfaces generated is including them in partial class that sits alongside the generated DTOs which define the interfaces you want each DTO to share, e.g:
public partial class MyDto : IMyInterface {}
The previous behavior of not exporting implemented interfaces can be reverted with:
var nativeTypes = this.GetPlugin<NativeTypesFeature>();
nativeTypes.MetadataTypesConfig.ExcludeImplementedInterfaces = true;
Related
ServiceStack has support for OpenAPI and can generate an OpenAPI spec. However, for APIs/endpoints to be generated in the spec, it is not enough to specify the API details using the Route attributes as described here, you also need to create the Service classes that (eventually) implement the functionality.
Is there a way to make the OpenAPI specification include everything without having to create the Service classes that go with them?
The reason is that sometimes you just want to work on the specification, not implementation (even though you can just skip implementation details and throw a NotImplementedException), and creating those Service classes just to get the spec to show is annoying.
If it doesn't have an implementation it's not a Service and therefore wont have any of ServiceStack's metadata or features available for it.
If you want to skip their implementation you can just create stub implementations for them, e.g:
public class MyServices : Service
{
public object Any(MyRequest1 request) => null;
public object Any(MyRequest2 request) => null;
public object Any(MyRequest3 request) => null;
}
What is the difference between attributes such as [RequireRole("admin")] and [ValidateHasRole("admin")]?
https://docs.servicestack.net/authentication-and-authorization#requiredrole-and-requiredpermission-attributes
https://docs.servicestack.net/declarative-validation#type-validators
It does say in the docs:
ServiceStack includes built-in Type Validator attributes for all Authorization Filter Attributes but as they’re decoupled from any implementation they can be safely annotated on Request DTOs without requiring any implementation dependencies.
Which dependencies are those? As I understand, [RequireRole("admin")] can be put on the service or directly on the DTO.
The [RequireRole] is implemented by the RequiredRoleAttribute.cs Request Filter Attribute in ServiceStack.dll.
Your ServiceModel project containing your API DTOs should not have any concrete implementation assemblies like ServiceStack.dll so if you want to annotate your Request DTOs with Authentication attributes you should use the declarative fluent validation [Vaidate*] instead which exists in the impl-free ServiceStack.Interfaces.dll - i.e. the only ServiceStack .dll your Service Models (DTOs) should reference.
Using the first example in the ServiceStack Auto Query documentation in a project structured similar to the EmailContacts sample project (i.e. separate projects for the ServiceModel and ServiceInterface), how would one register the custom route "/movies" defined by the Route attribute?
[Route("/movies")]
public class FindMovies : QueryBase<Movie>
{
public string[] Ratings { get; set; }
}
Normally, custom routes such as these can be register by passing the ServiceInterface assembly when instantiating AppHostBase:
public AppHost() : base("Email Contact Services", typeof(ContactsServices).Assembly) {}
However, the FindMovies request DTO does not have an associated service and therefore won't be included. No routes are registered.
If I pass typeof(FindMovies).Assembly instead of or in addition to typeof(ContactsServices).Assembly, then the pre-defined route will be registered (i.e. shows up in the metadata, postman, etc.) but the custom route is still not registered (i.e. does not show up in the metadata, postman, etc.).
What is the best way to register the custom route using attributes when there is no service and the ServiceModel and ServiceInterface are in separate projects?
These issues should be resolved in v4.0.24+ that's now available on MyGet.
There's a new AutoQueryFeature.LoadFromAssemblies property to specify an additional list of assemblies to scan for IQuery Request DTO's. This automatically looks in the assemblies where your other Request DTO's are defined so in most cases nothing needs to be done as it will automatically be able to find your query services.
The routes for Query DTO's should now appear on the metadata pages as well as Swagger and Postman metadata API's.
Was wondering if there's a recommended best-practice way of grouping similar services together in what's becoming a larger and larger project. Say that most of my services can be lumped in either dealing with "Pro" data or "Amateur" data (the data goes way beyond a simple flag in a table, the data itself is totally different, from different tables, on the pro or amateur side.
I know I can add routes to my classes...
/pro/service1
/am/service2
It looks like I can put the DTOs in namespaces....
What about the Service.Interface items (Service and Factory classes). Would you put those into namespaces also?
Finally, is there a way for the metadata page to reflect these groupings? I started to go down this road, but all the services listed out in alphabetical order, and you couldn't see the route or namespace differences between service1 and service2.
thank you
If you want, you can split multiple Service implementations across multiple dlls as described on the Modularizing Services wiki.
You can safely group service implementation classes into any nested folder groupings without having any impact to the external services. But changing the namespaces on DTO's can have an effect if your DTO's make use of object, interfaces or abstract classes which emit type info containing full namespaces.
In ServiceStack v4.09+ (now on MyGet) the MetadataFeature includes the ability to customize the ordering of the metadata page, e.g you can reverse the order of the metadata pages with:
var metadata = (MetadataFeature)Plugins.First(x => x is MetadataFeature);
metadata.IndexPageFilter = page => {
page.OperationNames.Sort((x,y) => y.CompareTo(x));
};
Organising your large project:
For a complex service(s) I setup 4 projects in one solution.
AppHost, This takes care of the configuration of the service. (References Model, Service and Types)
Model, This is the database model (Does not reference other projects)
Service, This is the implementation of the service only, not the interfaces or DTOs (References Model and Types)
Types, This includes my Interfaces, DTOs and routes. (Does not reference other projects)
Having a separate Types library allows the distribution to clients, for example for use with the ServiceStack JsonServiceClient.
Yes you can namespace the Interfaces, DTOs and factory classes, any way you want. They will work as long as they are referenced in your service correctly.
If you are trying to separate more than one service, you should consider separating your service code into logical folders within the Service project. i.e.
/Service/Pro
/Service/Amateur
Wrap the outer code of your Service methods in a public partial static class MyServiceStackApplication, with an appropriate name. Then reference this as the assembly in the AppHost constructor. So for example:
Pro Service (Service Project/Pro/UserActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Pro
{
public class UserActionsService : Service
{
public User Get(GetUserRequest request)
{
}
}
// ...
}
}
Pro Service (Service Project/Pro/OtherActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Pro
{
public class OtherActionsService : Service
{
public Other Get(GetOtherRequest request)
{
}
}
// ...
}
}
Amateur Service (Service Project/Am/UserActions.cs)
public partial static class MyServiceStackApplication
{
public partial class Amateur
{
public class UserActionsService : Service
{
public User Get(GetUserRequest request)
{
}
}
// ...
}
}
etc.
You can see from the above code we can have multiple files, all separated out and organised, but one assembly for ServiceStack to reference in the AppHost:
public AppHost() : base("Pro & Amateur Services", typeof(MyServiceStackApplication).Assembly) {}
Using the reference to the MyServiceStackApplication assembly, and using the partial keyword allows you to organise the code into manageable groupings.
Metadata:
Unfortunately separating the metadata by namespace isn't supported. You could try and customize the MetaDataFeature yourself, but it does seem like a useful feature, being able to separate multiple services where they are hosted in the one ServiceStack application. I would suggest you raise a feature request.
Mythz is bringing out features faster than lightning. :) Seems like he has that covered in the next release and you should be able to apply a custom filter to HostContext.Metadata.OperationNamesMap.
How do I configure my application so AutoMapper can map to internal types and/or properties in Silverlight 5? For example, I have the following type:
internal class SomeInfo
{
public String Value { get; set; }
}
I try to call Mapper.DynamicMap with this type as the destination and I receive the following error at runtime:
Attempt by security transparent method
'DynamicClass.SetValue(System.Object, System.Object)' to access
security critical type 'Acme.SomeInfo' failed.
I've tried instantiating the class first, then passing the instance to DynamicMap as well as changing the class scope to public with an internal setter for the property. I've also marked the class with the [SecuritySafeCritical] attribute. All of these tests resulted in the same error message.
The only way I've been able to get past this is to completely expose the class with public scope and public setters. This is, of course, a problem as I am developing a class library that will be used by other developers and using "internal" scope is a deliberate strategy to hide implementations details as well as make sure code is used only as intended (following the no public setters concept from DDD and CQRS).
That said, what can I do to make it so AutoMapper can work with internal types and/or properties?
(Note: The class library is built for SL5 and used in client apps configured to run out-of-browser with elevated trust.)
This is more of a Silverlight limitation - it does not allow reflection on private/protected/internal members from outside assemblies, see:
http://msdn.microsoft.com/en-us/library/stfy7tfc(VS.95).aspx
Simply put - AutoMapper can't access internal members of your assembly.