ServiceStack - Attribute knows what class it is calling from? - c#

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());

Related

ServiceStack IAppSettings was not ready and would result NULL reference exception if used in constructor

It seems like the IAppSettings implementation was not ready from IoC in the constructor.
Before I go into details, I've read similar problems:
ServiceStack doesn't auto-wire and register AppSettings
Instantiation of POCO objects with ServiceStack's IAppSettings is not working
Both were answered by #mythz that he was not able to reproduce it.
From the Doc
"ServiceStack made AppSettings a first-class property, which defaults to looking at .NET's App/Web.config's.": https://docs.servicestack.net/appsettings#first-class-appsettings
And there is default IoC registration already in Funq to give you AppSettings when you ask for IAppSettings:
What I have
All my codes are in the repo: https://github.com/davidliang2008/MvcWithServiceStack
The demo app is just an ASP.NET MVC app (.NET 4.8) that built using the template, the simplest you can get, with ServiceStack (5.12.0) installed:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
new AppHost().Init();
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("MvcWithServiceStack", typeof(ServiceBase).Assembly) { }
public override void Configure(Container container)
{
SetConfig(new HostConfig
{
HandlerFactoryPath = "api";
}
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
}
}
Then I have a base class for the ServiceStack Service, and a HelloService just to demo:
public abstract class ServiceBase : Service { }
public class HelloService : ServiceBase
{
public IAppSettings AppSettings { get; set; }
public object Get(HelloRequest request)
{
return new HelloResponse
{
Result = $"Hello, { request.Name }! Your custom value is { AppSettings.Get<string>("custom") }."
};
}
}
[Route("/hello/{name}")]
public class HelloRequest : IReturn<HelloResponse>
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
What works
When you're not using IAppSettings in the constructor, whether in the HelloService or its base class ServiceBase, everything works out fine.
When you clone the project to your local, if you navigate to /api/hello/{your-name}, you will see its response would be able to get the custom value from web.config:
What doesn't work
When you're trying to get the IAppSettings and initialize something else with some app setting values in the constructor - whether it's in the child class or the base class, IAppSettings will fail to get the implementation from IoC, and result a NULL reference exception:
public abstract class ServiceBase : Service
{
public IAppSettings AppSettings { get; set; }
public ServiceBase()
{
// AppSettings would be NULL
var test = AppSettings.Get<string>("custom");
}
}
OR
public class HelloService : ServiceBase
{
public HelloService()
{
// AppSettings would be NULL
var test = AppSettings.Get<string>("custom");
}
}
You cannot use any property dependency in the constructor since the properties can only be injected after the class is created and the constructor is run.
You'll only be able to access it in the Constructor by using constructor injection, e.g:
public class HelloService : ServiceBase
{
public HelloService(IAppSettings appSettings)
{
var test = appSettings.Get<string>("custom");
}
}
Or accessing the dependency via the singleton:
public class HelloService : ServiceBase
{
public HelloService()
{
var test = HostContext.AppSettings.Get<string>("custom");
}
}

.Net Core Dependency Injection Get different instance generated by Two Factory Methods

I have two static classes with single static factory method for each.
public static class First
{
public IMyService Factory()
{
return IMyService()
{
//configure with Configs
};
}
}
public static class Second
{
public IMyService Factory()
{
return IMyService()
{
// configure with different Configs
};
}
}
The following would make provider return an instance when asked for:
services.AddSingleton(mb =>
{
var myService= First.Factory();
return myService;
});
How do I call different factories when need to get an instance with different configs?
If it's a one-time decision (app startup) than you should extract your config as a dependency:
in appsettings.json:
"mysettings":{"bla":"val1"}
somewhere in project:
public class mysettings { public string bla {get;set; }
in myservice constructor:
public myservice(IOptions<mysettings> settings) { ... }
in startup.cs:
services.Configure<mysettings>(this.Configuration.GetSection("mysettings"));
services.AddSingleton<Imyservice, myservice>();
Like this you inject the settings and your service will be instantiated with those that are specified in the appsettings.json
If you need to deside "live" which settings to use:
public interface IMyServiceFactory{
IMyService Create(MySettings settings);
}
Than you inject IMyServiceFactory to the class where you want to use IMyService and instantate it there with the right settings. Or even:
public interface IMyServiceFactory{
IMyService Create1();
IMyService Create2();
}
In any case you just register the factory in startup:
services.AddSingleton<IMyServiceFactory, MyServiceFactory>();
Somehow your client code or the bootstrapping code needs to express what kind of implementation is needed. You could implement it the following way:
public Interface IReqeust
{
// Some code
}
public class HttpRequest : IRequest
{
// Implementation
}
public class TcpRequest : IRequest
{
// Implementation
}
One way could be to offer multiple methods. You can still hide the configuration but some implementation details leak into your client code.
public Interface IRequestFactory
{
IRequest CreateHttpRequest();
IRequest CreateTcpRequest();
}
public class RequestFactory : IRequestFactory
{
// Implementation
}
Another solution would be to determine whats needed while constructing your factory.
public Interface IRequestFactory
{
IRequest CreateRequest();
}
public class RequestFactory : IRequestFactory
{
private IConfigReader configReader;
public RequestFactory(IConfigReader configReader)
{
this.configReader = configReader;
}
public IRequest CreateRequest()
{
var currentProtocoll = configReader.GetCurrentProtocoll();
if(currentProtocoll is HTTP)
return new HttpRequest();
else
return new TcpRequest();
}
}
I would not recommend your solution with more factories. At least not with what you wrote so far.

How do i get values from appsettings.json to BusinessLayer(my helper class) MVC 6

My controller which returns user details by calling an API intern
public class HomeController : Controller
{
public ActionResult AccountDetails(int userId)
{
return this.Content(new WebHelperService().GetAccountDetails(userId)), "application/json");
}
}
Here is my WebHelperService which is in Business Layer, where i need to get value from appsettings.json
public class WebHelperService
{
private string url = null;
public WebHelperService()
{
//url = ConfigurationManager.ConnectionString["ExternalApiUrl"].ToString();
// ConfigurationManager is not available in .net core.
//So How do i read ExternalApiUrl from appsettings.josn,Which is the best way
}
public string GetAccountDetails(int userId)
{
return WebCall("{'userId':" + userId + "}");
}
private string WebCall(string data)
{
WebRequest request = WebRequest.Create(url);
// get the data from url and returns it
}
}
Do I need to carry settings all the way from controller in mvc6?
Reference : learn.microsoft.com/en-us/aspnet/core/mvc/con..)
Let's forget for a moment your particular use case and just talk about settings in .net core in general. Importantly, I think you are trying to access the raw AppSettings from your class, but what you actually want to do is DI them into your class. So let's do that.
Consider you have a appSettings.json that resembles something like below :
{
"myConfiguration": {
"myProperty": true
}
}
Now you need to create a POCO to hold these settings. Something like so :
public class MyConfiguration
{
public bool MyProperty { get; set; }
}
In your startup.cs you should have a method called "ConfigureServices". In there you are going to place a call to "configure" your settings like so.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
}
And so now you want to inject that settings object into a class. Let's call it MyClass for now. It would look like the following :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(IOptions<MyConfiguration> myConfiguration)
{
_myConfiguration = myConfiguration.Value;
}
}
Now you have access to your configuration!
Bonus!
Instead you can make your ConfigureServices method look like the following :
public void ConfigureServices(IServiceCollection services)
{
//services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
services.AddSingleton(Configuration.GetSection("myConfiguration").Get<MyConfiguration>());
}
What this now does is bind your services onto an actual class, not the IOptions object.
Now when you inject it into your class, you instead inject the POCO settings class, not IOptions. Like so :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(MyConfiguration myConfiguration)
{
_myConfiguration = myConfiguration;
}
}
For further reading :
http://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration

ServiceStack 3.9.17.0 Implementing IAsyncService

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; }
}

Handle specific HTTP answers correctly (OOP specific)

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();
}
}

Categories