We are currently using ServiceStack as our core framework for service provisioning.
Does anyone know if it's possible to wrap custom exceptions into custom ErrorResponse objects?
From SS wiki:
"In addition to the above options, you can override the serialization of ad-hoc exceptions by implementing the IResponseStatusConvertible.ToResponseStatus() method and have it return your own populated ResponseStatus instance instead."
That seems to fit with my needs, but I cannot figure out where I can override this serialization.
Again, I've tried to use custom httphandler by registering them within the AppHost, but they are not invoked when exceptions occur.
I am certainly missing something, is there anyone who can guide me through this?
Here is ServiceStack's Error Handling wiki page.
What it's saying is that you can control how the ResponseStatus is serialized if your custom exceptions implement IResponseStatusConvertible. Here is the source code example of ValidationException implementing it:
public class ValidationException : ArgumentException, IResponseStatusConvertible
{
public IEnumerable<ValidationFailure> Errors { get; private set; }
public ValidationException(IEnumerable<ValidationFailure> errors) : base(BuildErrorMesage(errors)) {
Errors = errors;
}
private static string BuildErrorMesage(IEnumerable<ValidationFailure> errors) {
var arr = errors.Select(x => "\r\n -- " + x.ErrorMessage).ToArray();
return "Validation failed: " + string.Join("", arr);
}
public ResponseStatus ToResponseStatus()
{
var errors = Errors.ConvertAll(x =>
new ValidationErrorField(x.ErrorCode, x.PropertyName, x.ErrorMessage));
var responseStatus = ResponseStatusUtils.CreateResponseStatus(typeof(ValidationException).Name, Message, errors);
return responseStatus;
}
}
But this only controls how ResponseStatus is serialized, not how the generic responses are created. Look at the description of IAppHost.ServiceExceptionHandler or use a custom service runner if you want to change the error response returned.
Related
What is the best practice for placing business logic in message based design?
Im using servicestack for building my api.
The wiki shows the example of placing the RequiredRole Attribute on the message instead of the service handling it.
In a sense this [RequiredRole]/[Authenticate] is business logic/security attached to the message.
Concrete example
Say for example i would add DeleteAddress message:
public class DeleteAddress : IReturn<bool>
{
public int AddressId { get; set; }
}
But for this to be properly secure i want to check either Admin Role, permission to ManageAllAddresses or that the AddressId is linked to this user (maybe in session, maybe through a db call).
How would i best go about this?
Proposition
Is the following code the good practice and if so how would i implement it?
[RequiredRole("Admin")]
[RequiredPermission("ManageAllAddresses ")]
[RequiredAddressLinkedToAccount]
public class DeleteAddress : IReturn<bool>
{
public int AddressId { get; set; }
}
ServiceStack's recommendation is to keep your ServiceModel free of dependencies so we'd recommend to annotate your Service implementation classes instead which you can annotate either on the Service class to apply to all Operations or on the individual methods to apply just to that operation, e.g:
[RequiredRole("Admin")]
public class AddressServices : Service
{
[RequiredPermission("ManageAllAddresses ")]
[RequiredAddressLinkedToAccount]
public object Any(DeleteAddress request)
{
}
}
Please note ServiceStack requires your Services to return reference types, which is typically a Response DTO but can also be a string, e.g:
public class DeleteAddress : IReturn<string>
{
public int AddressId { get; set; }
}
To finish of this question. I could make a request filter and add it on the service.
Either inherit from AuthenticateAttribute or Directly from RequestFilterAttribute.
public class RequiredAddressLinkedToAccount : AuthenticateAttribute
{
public RequiredRoleAttribute(ApplyTo applyTo)
{
this.ApplyTo = applyTo;
this.Priority = (int)RequestFilterPriority.RequiredRole;
}
public override void Execute(IRequest req, IResponse res, object requestDto)
{
var dto = requestDto as ILinkedToAccount;
var session = req.GetSession();
if(dto.AccountId == session.Id)
return; //we dont want anything to be blocked if the account Id is there.
//Implement like RequireRoleAttribute
if (DoHtmlRedirectIfConfigured(req, res))
return;
res.StatusCode = (int)HttpStatusCode.Forbidden;
res.StatusDescription = "Address does not belong to you";
res.EndRequest();
}
}
ServiceStack.Funq.Quartz Sample Code is
public class MyServices : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, {0}!".Fmt(request.Name) };
}
}
public class HelloJob : IJob
{
private MyServices MyServices { get; set; }
public HelloJob(MyServices myServices)
{
MyServices = myServices;
}
public void Execute(IJobExecutionContext context)
{
var response = MyServices.Any(new ServiceModel.Hello
{
Name = "CodeRevver"
});
response.PrintDump();
}
}
The above is works fine. if I in the MyServices Class, removed the Any function, and comment the Execute inner code.
public class MyServices : Service
{
}
the quartz.net will get the error:
[Quartz.Core.ErrorLogger】 An error occurred instantiating job to be executed. job= 'JobGroup1.GetUserJob111' Problem instantiating type 'ServiceStackWithQuartz.HelloJob'
why the class must have public object Any(Hello request) function ?
Thanks for using the package – I had no idea that other people would find it useful.
So If I understand correctly, in your situation you have:
public class MyServices : Service
{
}
And you’re trying to resolve this Service via constructor injection, which is effectively doing a:
container.Resolve<MyServices>();
This will fail because of the way the ServiceStack Funq IoC works. You can’t resolve a ServiceStack Service that has nothing in it (you'd probably never want to either) – It has to at least have one service implementation, It doesn’t matter what the implementation is.
Also, if you want to improve ServiceStack.Funq.Quartz, feel free to contribute to the code base.
Edit: It's probably worth mentioning that you can inject a "Non-Service" class with your logic in it if you want. You can resolve other classes that aren't based off of ServiceStack.Service even if there's nothing in them.
Edit 2: Responding to your "Service wont dispose" problem. This is the same across ServiceStack and has nothing to do with your Quartz Job. If you call a:
container.Resolve<MyServices>().Any(new new ServiceModel.Hello { });
from AppHost for example, your service wont dispose by itself. If you want it to dispose you can wrap it in a using statement. e.g.
using (var service = MyServices)
{
var response = MyServices.Any(new ServiceModel.Hello { });
}
The using will ensure that your service will be disposed afterwards.
Alternatively you can add the interface "IDispose" on to your Quartz Job and implement a Dispose() method that will do a:
MyServices.Dispose();
This will be called after a job has executed.
We're working on a project using ServiceStack (loving it) but need some help with a strange problem. In our project we throw or return various types of HttpError with ErrorResponse and ResponseStatus objects using a helper method.
It follows the pattern described here. Something like this:
protected HttpError BusinessError(string summaryMessage = "Some generic validation summary.")
{
return new HttpError(HttpStatusCode.BadRequest, "MyValidationType", summaryMessage)
{
Response = new ErrorResponse
{
ResponseStatus = new ResponseStatus
{
ErrorCode = "MyValidationType",
Message = summaryMessage,
Errors = new List<ResponseError>()
},
}
};
}
In a service call we would use it like so:
throw BusinessError("Help I've fallen and can't get up!");
This would work a treat, and we'd feed it in to the ss-validation JS library to render our validation messages. Worked fine.
The problem is that now ServiceStack won't serialize any of the HttpError's details into the response. All we get is a response with the 400 status code, the 'MyValidationType' error code, and empty JSON response {}.
I've tried playing with combinations of throwing/returning the error and switching the service method's return type to object etc, but nothing seems to make a difference. To be honest I'm not sure what we could have changed in our project to cause this behavior.
I'd appreciate any advice or pointers as to what could cause this?
This can happen if you're using a {RequestName} and {RequestName}Response naming convention and the Response DTO does not have a ResponseStatus property:
The {RequestDto}Response is returned, regardless of the service method's response type. If the {RequestDto}Response DTO has a ResponseStatus property, it is populated otherwise no ResponseStatus will be returned. (If you have decorated the {ResponseDto}Response class and properties with [DataContract]/[DataMember] attributes, then ResponseStatus also needs to be decorated, to get populated).
In which case the solution is just to add a ResponseStatus property to the Response DTO:
public class RequestNameResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
I just downloaded ServiceStack with NuGet. Version 3.9.56.
I am trying simple webservice but when i open metadata json page it gives NullReferenceException error.
My service is here:
[Route("/users")]
[Alias("Users")]
public class User
{
[Alias("UserID")]
public int id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
public class UsersService:Service
{
public object Get(User request)
{
var result = new List<User>();
result = Db.Select<User>();
return result;
}
}
There is a known issue that might explain your null reference exception. However, you do not want IReturnVoid, unlike in your other post, so the answer here is not to wait for ServiceStack to be fixed but to improve your DTO's declaration:
Your UsersService implementation is returning a List<User> object for your User request. You can document this in ServiceStack like so:
public class User : IReturn<List<User>>
{
...
}
This may fix the issue you are seeing on the metadata page as ServiceStack now knows the type of response to expect for the User message. There are other benefits to decorating your request DTOs with IReturn:
The typed C# client will be easier to use, as the client can know the type of your response message
The Swagger UI, if you use it, will know about and automatically document the response type
We have been using ServiceStack for REST based services for a while now and so far it has been amazing.
All of our services have been written as:
public class MyRestService : RestService<RestServiceDto>
{
public override object OnGet(RestServiceDto request)
{
}
}
For each DTO we have Response equivalent object:
public class RestServiceDto
{
public ResponseStatus ResponseStatus {get;set;}
}
which handles all the exceptions should they get thrown.
What I noticed is if an exception is thrown in the OnGet() or OnPost() methods, then the http status description contains the name of the exception class where as if I threw a:
new HttpError(HttpStatus.NotFound, "Some Message");
then the http status description contains the text "Some Message".
Since some of the rest services are throwing exceptions and others are throwing new HttpError(), I was wondering if there was a way without changing all my REST services to catch any exceptions and throw a new HttpError()?
So for example, if the OnGet() method throws an exception, then catch it and throw a new HttpError()?
Using Old API - inherit a custom base class
As you're using the old API to handle exceptions generically you should provide a Custom Base class and override the HandleException method, e.g:
public class MyRestServiceBase<TRequest> : RestService<TRequest>
{
public override object HandleException(TRequest request, Exception ex)
{
...
return new HttpError(..);
}
}
Then to take advantage of the custom Error handling have all your services inherit your class instead, e.g:
public class MyRestService : MyRestServiceBase<RestServiceDto>
{
public override object OnGet(RestServiceDto request)
{
}
}
Using New API - use a ServiceRunner
Otherwise if you're using ServiceStack's improved New API then you don't need to have all services inherit a base class, instead you can just tell ServiceStack to use a custom runner in your AppHost by overriding CreateServiceRunner:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext);
}
Where MyServiceRunner is just a just custom class implementing the custom hooks you're interested in, e.g:
public class MyServiceRunner<T> : ServiceRunner<T> {
public override object HandleException(IRequestContext requestContext,
TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}