I am attempting to implement the IAsyncService interface with ServiceStack 3.9.17.0.
Here is the code for my service definition:
public class TestService : IAsyncService<int>
{
object IAsyncService<int>.ExecuteAsync(int request)
{
return "Yup that worked";
}
}
And here is the code from my Global.asax.cs:
public class Global : System.Web.HttpApplication
{
public class TestServiceAppHost : AppHostBase
{
public TestServiceAppHost() : base("Test Async Web Services", typeof(TestService).Assembly) { }
public override void Configure(Funq.Container container)
{
Routes.Add<int>("/Test");
}
}
}
When I run and go to the metadata page I see the other 2 services that exist in this project which just implement IService (removed to keep samples clean) but my IAsyncService doesn't display and if i try to hit it i get the following message:
<Int32Response xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="">
<ResponseStatus>
<ErrorCode>KeyNotFoundException</ErrorCode>
<Message>The given key was not present in the dictionary.</Message>
<StackTrace>
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at ServiceStack.WebHost.Endpoints.Utils.FilterAttributeCache.GetRequestFilterAttributes(Type requestDtoType)
at ServiceStack.WebHost.Endpoints.EndpointHost.ApplyRequestFilters(IHttpRequest httpReq, IHttpResponse httpRes, Object requestDto)
at ServiceStack.WebHost.Endpoints.RestHandler.ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, String operationName)
</StackTrace>
</ResponseStatus>
</Int32Response>
Any and all help would be greatly appreciated.
EDIT:
I have update the code to look like this after a suggestion from mythz (thanks again for replying).
DTO and Service:
[Route("/test")]
public class TestDTO
{
public int request { get; set; }
}
public class TestService : IAsyncService<TestDTO>
{
object IAsyncService<TestDTO>.ExecuteAsync(TestDTO request)
{
return "Yup that worked";
}
}
I left the Global.asax.cs the same except i changes the route to use the DTO and made the route lower case to match the attribute on the DTO. I am still having the same issue.
Edit #2:
I upgraded to v3.9.71 and am still having the same issue.
ServiceStack Services require a Request DTO, i.e. a concrete POCO class. You cannot use an int as a Request DTO. If you need to you can wrap it in a POCO class, e.g:
[Route("/test")]
public class Request
{
public int Int { get; set; }
}
Related
I am using Ninject 3 in an MVC5-based website, and trying to work out how to get DI to work with a type that tests properties of a Uri.Host value passed into its constructor. I'd like the binding to somehow provide the current URL. The minimal structure I've tried initially is:
public class StructuredUrlTester : IStructuredUrlTester
{
// Expose public getters for parts of the uri.Host value
bool MyBooleanProperty { get; private set; }
public StructuredUrlTester(Uri uri)
{
// Test the value of uri.Host and extract parts via regex
}
}
// In Global.asax.cs
public class MvcApplication : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
kernel.Bind<IStructuredUrlTester>()
.To<StructuredUrlTester>()
.InTransientScope();
.WithConstructorArgument("uri", Request.Url);
}
}
// In MyController.cs
public class MyController : Controller
{
private readonly IStructuredUrlTester _tester;
public ContentPageController(IStructuredUrlTester tester)
{
this._tester = tester;
}
public ActionResult Index()
{
string viewName = "DefaultView";
if (this._tester.MyBooleanProperty)
{
viewName = "CustomView";
}
return View(viewName);
}
}
As the CreateKernel() call happens before the Request object is available, the .WithConstructorArgument() part throws an exception ("System.Web.HttpException: Request is not available in this context").
How can I provide the binding of interface to concrete type, whilst also being able to provide the e.g. HttpContext.Current.Request.Url value (available within the Controller) to the constructor of the concrete type, at run-time when it's available?
Wrap the desired functionality in an abstraction:
public interface IUriProvider {
Uri Current { get; }
}
Refactor the tester class:
public class StructuredUrlTester : IStructuredUrlTester {
// Expose public getters for parts of the uri.Host value
bool MyBooleanProperty { get; private set; }
public StructuredUrlTester(IUriProvider provider) {
Uri uri = provider.Current;
// Test the value of uri.Host and extract parts via regex
}
}
The provider implementation should wrap the Request.Url:
public class UriProvider : IUriProvider {
public Uri Current { get { return HttpContext.Current.Request.Url; } }
}
And note that the Current property should actually be called within the action of a controller where HttpContext and its request are available.
I need to access request context, specifically the Items inside my custom class and I don't want to do have it either inheriting from ServiceStack Service or having the set it up inside the my Service.
So if I have a class like below which the implementer class (ContextItemsGetter) also implements IRequiresRequest, I would expect the Request property to be populated.
public interface IGetContextItems
{
string Get(string key);
}
public class ContextItemsGetter : IGetContextItems, IRequiresRequest
{
public string Get(string key)
{
//someway to access http context items
//im RequestContext.Instance.Items[key] e.g. Prop1 Prop2
//or Request.blah but Request is always null
}
public IRequest Request { get; set; }
}
https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Interfaces/Web/IRequiresRequest.cs
However the Request is always null for both when SessionIdGetter is called from a genuine HTTP request or a redis message request. Am I doing something wrong? The purpose is to decouple and use Items to pass information between http request and redis message request.
I've also tried to use RequestContext.Instance.Items, where this worked for HTTP request, but during redis message request, the items are not there, the keys where I populated just before calling ExecuteMessage are not there.
var req = new BasicRequest { Verb = HttpMethods.Get };
req.Items.Add("Prop1", m.GetBody().Prop1);
req.Items.Add("Prop2", m.GetBody().Prop2);
var result = HostContext.ServiceController.ExecuteMessage(m, req);
I'm using version 4.0.50.
Also, this page Access HTTP specific features in services where mentions
Note: ServiceStack's Service base class already implements IRequiresRequestContext which allows you to access the IRequestContext with base.RequestContext and the HTTP Request and Response with base.Request and base.Response.
I believe IRequiresRequestContext is now called IRequiresRequest, so I think the doc should be updated.
Updated: full code to demo my original intention:
[Route("/test", Verbs = "GET")]
public class Dto : IReturnVoid
{ }
public class DtoService : Service
{
//So that IGetContextItems is taken care of by IDependencyThatUsesIGetContextItems
public IDependencyThatUsesIGetContextItems DependencyThatUsesIGetContextItems { get; set; }
public void Get(Dto req)
{
DependencyThatUsesIGetContextItems.SomeMethod();
}
}
public interface IGetContextItems
{
string Get(string key);
}
//since ContextItemsGetter implmeents IRequiresRequest
//I can still easily test any service that uses IGetContextItems by mocking IGetContextItems
public class ContextItemsGetter : IGetContextItems, IRequiresRequest
{
public IRequest Request { get; set; }
public string Get(string key)
{
//either through injection
//return Request.Items[key].ToString();
//or some static class
//return RequestContext.RequestItems.Items[key].ToString();
return RequestContext.Instance.Items[key].ToString();
}
}
public interface IDependencyThatUsesIGetContextItems
{
string SomeMethod();
}
public class DependencyThatUsesIGetContextItems : IDependencyThatUsesIGetContextItems
{
//this will be inejcted
public IGetContextItems ContextItemsGetter { get; set; }
public string SomeMethod()
{
var a = ContextItemsGetter.Get("SomeKey");
return "blah";
}
}
IRequiresRequest only injects the current IRequest to your Service classes and Validation Filters, it doesn't inject the IRequest into your dependencies which are resolved directly from the IOC and who doesn't have access to current IRequest to be able to inject.
Also ServiceStack's convenient Service and AbstractValidator<T> base classes already implement IRequiresRequest so in most cases the places where IRequiresRequest applies has already been implemented so you shouldn't need to implement it yourself.
The recommended approach to passing the IRequest into your dependencies is to pass them as a parameter from your Service, e.g:
public class MyServices : Service
{
public IGetContextItems ContextItems { get; set; }
public object Get(Request request)
{
return ContextItems.Get(base.Request, request.Id);
}
}
You do have an opportunity to inspect and modify your Service instance before it executes your Service by overriding OnPreExecuteServiceFilter() in your AppHost to go through and inject the IRequest in each of your Services dependencies that implement IRequiresRequest with:
public override object OnPreExecuteServiceFilter(IService service,
object request, IRequest req, IResponse res)
{
service.InjectRequestIntoDependencies(req);
return request;
}
Which calls the below extension method will recursively populate your Services dependency graph as long as each parent implements IRequiresRequest:
public static class ServiceExtensions
{
public static void InjectRequestIntoDependencies(this object instance, IRequest req)
{
foreach (var pi in instance.GetType().GetPublicProperties())
{
var mi = pi.GetGetMethod();
if (mi == null)
continue;
var dep = mi.Invoke(instance, new object[0]);
var requiresRequest = dep as IRequiresRequest;
if (requiresRequest != null)
{
requiresRequest.Request = req;
requiresRequest.InjectRequestIntoDependencies(req);
}
}
}
}
But you need to be careful to not implement IRequiresRequest on any of your Singleton dependencies (the default scope) as it's not ThreadSafe whereas passing IRequest as a parameter would be.
Also to avoid coupling your logic classes to ServiceStack I'd consider only passing in what your dependencies needs from IRequest instead of the IRequest instance itself which will also make it easier to test.
Currently I'm writing a bot for a browsergame and there are several responses.
They are unencrypted and the data is provided by a normal http response.
So because there are severaly slightly different response-types and structures I thought I could use my (low) oop knowledge to handle this - but my concept does not work.
I thought I can make for each request (login request, logout request, attack request, harvest request, ..) a own class which is a child from the basic request class.
And the same concept I thought I can do for the responses.
So here is a small demo of my code:
public class BasicRequest
{
public BasicRequest(string serverId) { }
public virtual BasicResponse DoRequest(string[] requestData)
{
// request is handled here
}
}
public class LoginRequest : BasicRequest
{
public LoginRequest(string serverId) : base(serverId) { }
}
public class BasicResponse
{
public BasicResponse(string[] responseData) { }
public virtual void DoSomeStuffWithTheResponse() { }
}
public class LoginResponse : BasicResponse
{
public LoginResponse(string[] responseData) : base(responseData) { }
public override void DoSomeStuffWithTheResponse() { }
}
This is my basic structure (ofc I have some more request and response classes).
Now I tried to use it like this:
LoginResponse response = new LoginRequest("serverXX").DoRequest(new string[] { "data" }) as LoginResponse;
But then 'response' is just null.
The important thing is, that it should perform the actions that the constructor of the base class do (this is some basic stuff that every request and response need) and then the constructor and the override of the specific class (loginrequest/response in this case) should be called.
Hope you can help me out, thanks in advice.
Since you haven't overriden DoRequest in your LoginRequest class, when you invoke DoRequest the base classes implementation is being called.
In order for this to work, LoginRequest needs to override the base implementation:
public class LoginResponse : BasicResponse
{
public LoginResponse(string[] responseData) : base(responseData) { }
public override void DoSomeStuffWithTheResponse()
{
}
public override BasicResponse DoRequest(string[] requestData)
{
// Do stuff
return new LoginResponse();
}
}
Say, I have a LogAttribute class like this:
public class LogAttribute : RequestFilterAttribute {
public override void Execute(IHttpRequest req,
IHttpResponse res,
object dto) { /*...*/ }
}
[Log]
public class TransportService : Service { /*...*/ }
[Log]
public class HealthService : Service { /*...*/ }
How does the LogAttribute class know what class it is calling from? Namely, TransportService or HealthService?
You can use the Request DTO that's passed in as well as the metadata ServiceStack maintains about your service, e.g:
var serviceType = HostContext.Metadata.GetServiceTypeByRequest(dto.GetType());
I am just starting to familiarise myself with ServiceStack and have come upon FluentValidation. I have followed the introductions and created a small Hello App.
My problem is that when I try to validate the request DTO no error messages are returned to describe how it failed validation, only a blank Json object {}.
Myself, I think the validation is autowired to the DTO so there should be no need for me to write any extra code.
The answer is probably blatant but I cannot see it. Any help would be greatly appreciated. My code is below:
namespace SampleHello2
{
[Route("/hello")]
[Route("/hello/{Name}")]
public class Hello
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
public class HelloValidator : AbstractValidator<Hello>
{
public HelloValidator()
{
//Validation rules for all requests
RuleFor(r => r.Name).NotNull().NotEmpty().Equal("Ian").WithErrorCode("ShouldNotBeEmpty");
RuleFor(r => r.Name.Length).GreaterThan(2);
}
}
public class Global : System.Web.HttpApplication
{
public class HelloAppHost : AppHostBase
{
//Tell Service Stack the name of your application and where to find your web services
public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
public override void Configure(Funq.Container container)
{
//Enable the validation feature
Plugins.Add(new ValidationFeature());
container.RegisterValidators(typeof(HelloValidator).Assembly);
//register any dependencies your services use, e.g:
// container.Register<ICacheClient>(new MemoryCacheClient());
}
}
//Initialize your application singleton
protected void Application_Start(object sender, EventArgs e)
{
new HelloAppHost().Init();
}
}
}
P.S. Really enjoying using ServiceStack, It really is a fantastic project so thanks.
Edit
So for example:
Calling: http://localhost:60063/hello/Ian?format=json returns {"Result":"Hello, Ian"}.
Whereas Calling: http://localhost:60063/hello/I?format=json returns {}.
The second call returns {} where I was expecting auto generated error messages.
I found the answer. It was an overlook on my behalf:
This was in the documentation and I overlooked it:
All Error handling and validation options described below are treated
in the same way - serialized into the ResponseStatus property of your
Response DTO making it possible for your clients applications to
generically treat all Web Service Errors in the same way.
So all that was missing from my code was to add the following line into the HelloResponse class.
public ResponseStatus ResponseStatus { get; set; }