Adding Request Headers to a manually instantiated ServiceStack object? - servicestack

using(var service = new PlacementService())
{
service.Request.Headers.Add("Impersonated", "1"); //NULL Exception thrown
}
I need to be able to set a header on a manually instantiated ServiceStack class, but the request object is NULL so it's not working. It's being called inside a HttpPost Mvc Controller method.
The service was created to check a header to see if the request was coming from an impersonated user, it's just usually called directly from the frontend, I need to access a couple methods from it in backend code... this is the only thing tripping me up.

You can invoke Services with the Service Gateway or by using ResolveService from the ServiceStackController base class, e.g:
using var service = ResolveService<PlacementService>();
But the HttpRequestBase.Headers collection is immutable where you wouldn't be able to modify the HTTP Request collections. Instead you would typically populate the Items dictionary to pass additional info to the Service.
Otherwise you could populate the service with a custom IRequest which will let you construct your own Request context, e.g:
using var service = new PlacementService {
Request = new BasicRequest(requestDto)
}

Related

.NET 6.0 ServiceStack 6.1.1 JsonServiceClient doesn't use /json/reply

I have two application one is an API and is using SS v5.10.4 the other one is a service that was using SS v5.8.0 and was upgraded to v6.1.1
The service is referencing the API's DTOs using the ServiceStackVS plugin which creates a single *.dto file. Some of the DTOs in the API have custom routes others don't. Prior to upgrading the service to SS v.6.1.1 the calls using the DTOs without custom routes were going to /json/reply/{requestDTO} and the ones with custom routes were going to /{Route}. After the upgrade all calls are now going to /{requestDTO}. Any idea why that is and is there an easy way to default the JsonServiceClient to use the /json/reply/{requestDTO} if there isn't a custom route defined in the {myAPI}.dtos file for the specific DTOs ?
So seems like it's working as expected if I set the baseUri in the constructor of the JsonServiceClient instead of setting the BaseUri property.
Doesn't work:
_client = new JsonServiceClient
{
BaseUri = _configuration.ClientUri,
Timeout = TimeSpan.FromMinutes(_configuration.RequestTimeOut)
};
Works:
_client= new JsonServiceClient(_configuration.ClientUri)
{
Timeout = TimeSpan.FromMinutes(_configuration.RequestTimeOut)
};

Is there a way to remove the "/json/reply/" section of the url?

I would like the URL for a request to be /AmazingRequest (or even /AmazingService) instead of /json/reply/AmazingRequest.
I've tried the Route attribute, but it seems to have no effect. Is it possible within ServiceStack, or would I have to resort to URL rewriting?
This is what I've tried. It compiles, but the attribute has no effect.
public class MyServiceEndpoints : IService
{
[Route("/AmazingService")]
public AmazingResponse Post(AmazingRequest request)
{
return new Amazing(request).GetResponse();
}
}
I realize I would need to tell ServiceStack that it is a json request, but I'm fine with adding the Accept and Content-Type headers or maybe even a ?format=json to the query string.
P.S. I'm using the BSD version of ServiceStack
In ServiceStack Routes are defined on the Request DTO as it's part of your Service Contract, e.g:
[Route("/AmazingService")]
public class AmazingRequest { ... }
The pre-defined Route you're using is because ServiceStack doesn't think there's any custom route defined for your Service and just uses the default one.
The alternative way for declaring your Routes is to use the Fluent Registration API in your AppHost, e.g:
public void Configure(Container container)
{
Routes
.Add<AmazingRequest>("/AmazingService");
}
But the benefit of defining them on the Request DTO's is that your .NET Service Clients will also have access to them and will be able to use your custom routes instead of falling back to the pre-defined routes.

How to use Custom Routes with Auto Query

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.

Global request/response interceptor

What would be the easiest way to setup a request/response interceptor in ServiceStack that would execute for a particular service?
A request filter (IHasRequestFilter) works fine but a response filter (IHasResponseFilter) is not triggered if the service returns non 2xx status code. I need to retrieve the status code returned by the method as well as the response DTO (if any).
A custom ServiceRunner and overriding the OnBeforeExecute and OnAfterExecute methods seems to work fine but I find it pretty intrusive as the service runner need to be replaced for the entire application and I couldn't find a way clean way to isolate per functionality the tasks that need to be executed in those methods.
Is there some extension point in ServiceStack that I am missing that would allow me to execute some code before each service method and after each service method? A plugin would be ideal but how can I subscribe to some fictitious BeforeExecute and AfterExecute methods that would allow me to run some custom code?
UPDATE:
Just after posting the question I found out that global response filters are executed no matter what status code is returned by the service which is exactly what I needed. So one last question: Is it possible to retrieve the service type that will handle the request in a request filter? I need to check whether this service is decorated by some custom marker attribute.
I have found out a solution to my question about how to retrieve the service type in a custom request/response filter:
appHost.RequestFilters.Add((req, res, requestDto) =>
{
var metadata = EndpointHost.Metadata;
Type serviceType = metadata.GetServiceTypeByRequest(requestDto.GetType());
...
}
A custom ServiceRunner and overriding the OnBeforeExecute and OnAfterExecute methods seems to work fine but I find it pretty intrusive as the service runner need to be replaced for the entire application
Quick note, you can opt-in and choose only what requests should use a custom service runner, e.g:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return useCustomRunner(actionContext.RequestType)
? new MyServiceRunner<TRequest>(this, actionContext)
: base.CreateServiceRunner<TRequest>(actionContext);
}
IHttpRequest has OperationName. I think thats what you are after.

ServiceStack Request DTO with variable number of properties

I'd like to create an endpoint that is the front end for a query service and I'd like to support a scenario where any number of arguments can be passed into the service via querystring parameters.
This is the sort of URL I want:
/queries/MyQuery?argument1=value&arg2=value
The DTO object structure itself is fairly straightforward (a property such as Dictionary<string, object>) but I'm stuck on what the route should look like. Is this possible via the RouteAttribute or do I need to go another direction?
Here's a good answer that explains Routing in ServiceStack.
Only the PathInfo is apart of the Route, the Request DTOs on all routes/services are also automatically populated based on the Request Params on the QueryString/FormData etc.
So if you know what the QueryString is going to be you can just add it as properties on the Request DTO and they will get automatically populated.
If you don't know what they are, but you still want access to the QueryString you can get it from the base.Request property in your Service, e.g:
class MyServices : Service
{
public object Get(MyQuery request)
{
foreach (var entry in base.Request.QueryString) {
...
}
}
}

Resources