How to make this Spring Injection work - asp.net

I have this inside my spring xml file:
<object type="Test.Web.Utilities.TestClass, Test.Web" singleton="false" id="TestClass">
<property name="TestService" ref="TestService"/>
</object>
In the TestClass I have this:
public ITestService TestService { get; set; }
and this:
public void TestMethod()
{
var x = TestService.ExampleMethod();
}
next, inside my controller I have this:
TestClass t = new TestClass();
t.TestMethod();
However, I don't seem to get this to work. other spring related stuff on the controller works well.
Any ideas how can I get this to work?
EDIT: Forgot to add, the error I get is a NullReferenceException

This cannot work since you're creating TestClass instance via new and Spring is of course not aware to inject dependencies into objects created via the frameworks new. You'll not find a .NET IOC framework that can do this (for good reasons!).
So what you need to do is to inject instances of TestClass into your controller. You could register these instances with a request or prototype scope.

You cannot use the normal "new" keyword, because this is handled via the .NET VM. You actually need to call Spring's Activator Context to give you an instance.
First you acquire the Spring.NET Activator context by calling:
IApplicationContext ctx = ContextRegistry.GetContext();
Then you can get an instance of your class specified in your configuration xml:
ITestService svc = (ITestService)ctx.GetObject("TestClass");
This enables you to configure via your XML file what concrete implementation class that implements the ITestService interface.

Related

Why is the IConfiguration object null after injecting it to DbContext? [ASP.NET Core 3.1]

Before posting this question I have gone through multiple posts that are similar. My question focuses on "why is it happening despite applying the common and possibly right solution?".
I am developing a .NET Core 3.1 web app. I have a DbContext named 'SkipQContext'. I am trying to access the connection string from appsettings.json in the SkipQContext file using Configuration object.
For that, I have injected IConfiguration as a service to the SkipQContext constructor.
Constructor:
private readonly string ConnectionString;
public SkipQContext()
{
}
public SkipQContext(DbContextOptions<SkipQContext> options, IConfiguration configuration)
: base(options)
{
ConnectionString = configuration.GetConnectionString("DefaultConnection");
}
I have also registered in ConfigureServices method of Startup class.
services.AddSingleton(Configuration);
Now when I instantiate SkipQContext in one of my repository classes, the default constructor of SkipQContext is called. When I try to fetch data using it, I get the "IConfiguration object is null."
I applied breakpoints in ConfigureServices method and can see that the IConfiguration object has the connection string value.
My first question is, why is it null in SkipQContext when I am registering it in ConfigureServices and also injecting it in SkipQContext constructor? Multiple answers online state this as the right method.
Also, I am thinking, I might not be instantiating the SkipQContext rightly. As my statement :
SkipQContext db = new SkipQContext();
hits the default constructor of SkipQContext which is empty and not the overloaded constructor where IConfiguration is injected.
P.S. If the last question is dumb. I am still a bit unclear about how dependency injection works in .NET Core.
Also, I am thinking, I might not be instantiating the SkipQContext rightly. As my statement:
SkipQContext db = new SkipQContext();
hits the default constructor of SkipQContext which is empty and not the overloaded constructor where IConfiguration is injected.
You are right, this is not how dependency injection is supposed to work. Whenever you do new Something, then you are explicitly going around dependency injection. The main point about dependency injection is that a component that has a dependency (e.g. a database context) does not need to create that dependency itself, or even know how to create that dependency itself.
When you call new SkipQContext(), you are explicitly creating that depenndency, so you are tightly coupled to that SkipQContext and whatever that context needs in order to work properly (in this case, it needs DbContextOptions and IConfiguration). What you want instead is components to be loosely coupled to their dependencies. So you just declare what dependencies you need and require that someone or something else fulfills these dependencies for you. And that’s exactly where dependency injection comes in:
With dependency injection, you have a “dependency injection container” which takes care of creating all the dependencies that you or some component may require. You configure the container in a central location, in Startup.ConfigureServices, and then you are able to simply declare what dependencies you need via a service’s constructor. But in order for the container to provide these dependencies to that service, the service will have to be created by the container itself.
So what you will see is that you will basically have to consume everything through dependency injection. But this also makes it easy to realize when you are not using dependency injection: Whenever you write new Something, then that something won’t be created by the container and as such won’t have its dependencies automatically fulfilled. Depending on what that something is that might be what you want, or maybe not (e.g. creating a List<string> or a DTO object is something you want to do directly, creating a service or something that has other dependencies likely isn’t).
Coming back to your problem, in order to have the DI container take care of the dependencies in the constructor of SkipQContext, you will have to let the DI container create that context for you. So you cannot create it with new but instead you will have to depend on it by adding it to the constructor of whatever component you need it in.
E.g. if you have a controller, just add it as a dependency there:
public class HomeController : Controller
{
private readonly SkipQContext _db;
public HomeController(SkipQContext db)
{
_db = db;
}
public async Task<IActionResult> Index()
{
var items = await _db.Items.ToListAsync();
return View(new IndexViewModel
{
Items = items,
});
}
}
One final note regarding your database context: If you register the database context correctly with the DI container, then it will already be configured using the DbContextOptions that gets passed to the constructor. These options will also include the connection string the context needs to open the database connection. So you do not need to pass the IConfiguration manually or extract the connection string there. It will be automatically done for you by EF Core.
A proper context setup could look like this (in ConfigureServices):
services.AddDbContext<SkipQContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
There is no need to instantiate the Configuration as a Singleton, the Default builder of WebHost already inject the configuration in the request , your Startup Class should look like this
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
string conn = Configuration.GetConnectionString("NAME OF YOUR CONNECTION STRING IN THE application.json FILE");
services.AddDbContext<CLASSOFURDBCONTEXT>(config =>
{
config.UseSqlServer(conn);
});
}
}
And your dbcontext should have the following constructor
public YourDbContext(DbContextOptions<YourDbContext> options) : base(options)
{
}
Then you only need to call the DbContext in a controller or a service and the DI will do the rest
As per why your IConfiguration throw the null reference exception i can think of 2 possibilities. Either you need to do the other kind instanciation which would be like this
services.AddSingleton<IConfiguration,Configuration>();
Or maybe it is because you are not using DI into the DbContext itself, you shouldnt need to do the new YourContextDbContext(). You should just simply put it in the constructor of the service or controller and it should work "magically" without you actually need to make an instance of it.

Cloud datastore dynamic namespace

Requirement
For Cloud, datastore needs to change namespace dynamically. (example store kind as per company Name)
Used Spring cloud DataRepository with Springboot for same
Issue
We need to declare spring.cloud.gcp.datastore.namespace in application.properties which is static.
Is there any way to change this dynamically with CRUDReposity of spring cloud
Thanks in advance
You can change anything you want in your application.properties at runtime using Spring Cloud Config.
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
Just as a quick example on how you can use this , you should firstly add the dependency : eg gradlecompile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE', then you need to add the #RefreshScope on the desired configuration bean.
You will be able to view your current config at a certain endpoint, like "applicationConfig: [classpath:/application.properties]": {
"my.property": "value1",
etc
And then you can change the properties as you wish doing a POST request like :
curl -X POST http://localhost:8080 -d my.property=value2
There is also a nice article about dynamically reloading the properties in a Spring application here. It is nice because they actually display more ways that you can achieve that.
You can use DatastoreNamespaceProvider which can dynamically return needed namespace.
Was added in this PR PR
Also see this discussion here and this recommendation
#Component
#RequiredArgsConstructor
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class HeaderValueProvider implements Supplier<String>, DatastoreNamespaceProvider {
private final HttpServletRequest httpServletRequest;
#Override
public String get() {
return httpServletRequest.getHeader("someHeader");
}
}
And this
#Component
public class UserContextProvider implements DatastoreNamespaceProvider, Consumer<UUID> {
private static final ThreadLocal<UUID> USER_CONTEXT = new ThreadLocal<>();
#Override
public String get() {
return ofNullable(USER_CONTEXT.get())
.map(UUID::toString)
.orElse(null);
}
#Override
public void accept(UUID uuid) {
USER_CONTEXT.set(uuid);
}
}

Using Spring AOP 3.1.0 to set service instance using method argument

Hi i am new to Annotation and Spring AOP. below is what i am trying to achieve
public interface Service {
public void process(String ServiceName, Bean bean);
}
public class ServiceImpl1 implements Service{
public void process(String ServiceName, Bean bean) {
/// do something here
}
}
public class ServiceImpl2 implements Service{
public void process(String ServiceName, Bean bean) {
/// do something here
}
}
from other class i would be calling something like
...
public void doSomething(String serviceName, Bean bean){
service.process("ServiceImpl1", bean);
}
...
I can achieve the same by using AroundAdvice and Before advice and intercepting my doSomething method and then instantiate the service object after reading the serviceName.
I there is a better approach for this?
I just need a direction and then i will figure this out.
Thanks
Well, I am guessing what you want to do is have a Before advice that takes the passed in service name, creates an object of appropriate class, then calls the appropriate method on that newly created object. It seems like, to me, you are really looking for more of a Factory pattern, but trying to use AOP to accomplish it.
If you took the Factory pattern, you would create a class called ServiceFactory, which takes some parameters and returns the correct Service implementation for those parameters. You calling code would simply use the Factory to get the right Service at runtime.
Another approach, if you want to stick with more of a DI pattern, might be to create a wrapper class that serves as the "conductor". This might have a Map of service names to Service implementation. You could then inject this wrapper into your code, and even inject the Map into the wrapper. Your calling code would call methods on the wrapper, which would locate the correct, singleton implementation and aggrigate the call to it.
I just feel that using AOP for this is asking for trouble.
You can inject the service impl class using the spring #Autowire annotation. Since u have 2 implementation classes, you can use qualifier to specify which impl needs to b injected.

Using Autofac for DI into WCF service hosted in ASP.NET application

I'm having trouble injecting services dependencies into my WCF service using Autofac 1.4.5. I've read and followed the Autofac wiki page on WcfIntegration but my debugging shows me that my WCF service is created by the System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance() method and not by the AutofacWebServiceHostFactory. What am I doing wrong?
I've set up my ajax.svc file to look like the one in the example for use with WebHttpBinding:
<%# ServiceHost Language="C#" Debug="true"
Service="Generic.Frontend.Web.Ajax, Generic.Frontend.Web"
Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory,
Autofac.Integration.Wcf" %>
My WCF service class Ajax is defined like this:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
public MapWebService MapWebService { get; set;}
public Ajax() {
// this constructor is being called
}
public Ajax(MapWebService mapWebService)
{
// this constructor should be called
MapWebService = mapWebService;
}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
Now I've used the wiring up in the Global.asax.cs as shown in the wiki mentioned above:
var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModuleWebservice());
var container = builder.Build();
AutofacServiceHostFactory.Container = container;
with
class AutofacModuleWebservice : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<Ajax>();
builder.Register<MapWebService>().ContainerScoped();
}
}
In my web.config I have
<services>
<service name="Generic.Frontend.Web.Ajax">
<endpoint address="http://mysite.com/ajax.svc/" binding="webHttpBinding"
contract="Generic.Frontend.Web.Ajax" />
</service>
</services>
.
The service already works fine but I can't get the Autofac bits (read: creation/injection) to work. Any ideas?
Edit:
Removing the default constructor unfortunately leads to the following exception:
System.InvalidOperationException:
The service type provided could not be loaded as a service because it does not
have a default (parameter-less) constructor. To fix the problem, add a default
constructor to the type, or pass an instance of the type to the host.
Cheers, Oliver
Is your service setup with InstanceContextMode.Single? If it is then wcf will create your service using the default constructor. To get around this change your instance context mode and let autofac manage the lifetime of your service.
Try deleting the default Ajax constructor and modifying your constructor to this. If it gets run with mapWebService == null that would indicate a resolution problem.
public Ajax(MapWebService mapWebService = null)
{
// this constructor should be called
MapWebService = mapWebService;
}
I just got the same System.InvalidOperationException and solved it by changing the ServiceBehavior InstanceContextMode of the implementation from InstanceContextMode.PerCall to InstanceContextMode.PerSession, perhaps your AutoFac lifetime scope is out of sync with your web service implementation?
For testing AutoFac service creation I recommend creating a unit test and directly resolving them as this will highlight any issues and give more meaningful exception messages. For services with a request lifetime scope create a test aspx page and again resolve them directly.
I had the same problem and came across this question while searching for an answer.
In my case, using property injection worked, and the code in the question already has a property that can be used:
namespace Generic.Frontend.Web
{
[ServiceContract]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Ajax
{
// inject the dependency here
public MapWebService MapWebService { get; set;}
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract(Name = "mapchange")]
public MapChangeResult ProcessMapChange(string args)
{
// use the injected service here
var result = MapWebService.ProcessMapChange(args);
return result;
}
}
}
and register to use property injection (sample code from the wiki and syntax has changed as this is now using version 2.5.2.830):
builder.RegisterType<Ajax>().PropertiesAutowired();
Following the instructions solved it for me:
code.google.com/p/autofac/wiki/… I simply do : builder.RegisterType();
and I've followed their instuructions for changing the .svc file.
When you look at your .svc file you do not get any hints about something being wrong there btw?
You host it throu the iis and do not utilize WAS, I do not see your code for overriding global.asax.cs
Add the global file to your solution and there you implement:
protected void Application_Start(object sender, EventArgs e)
{
// build and set container in application start
IContainer container = AutofacContainerBuilder.BuildContainer();
AutofacHostFactory.Container = container;
}
AutofacContainerBuilder is my container builder.

Using Spring.Net to inject dependencies into ASP.NET MVC ActionFilters

I'm using MvcContrib to do my Spring.Net ASP.Net MVC controller dependency injection.
My dependencies are not being injected into my CustomAttribute action filter.
How to I get my dependencies into it?
Say you have an ActionFilter that looks like so:
public class CustomAttribute : ActionFilterAttribute, ICustomAttribute
{
private IAwesomeService awesomeService;
public CustomAttribute(){}
public CustomAttribute(IAwesomeService awesomeService)
{
this.awesomeService= awesomeService;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Do some work
}
}
With a Spring.Net configuration section that looks like so:
<object id="CustomAttribute " type="Assembly.CustomAttribute , Assembly" singleton="false">
<constructor-arg ref="AwesomeService"/>
</object>
And you use the Attribute like so:
[Custom]
public FooController : Controller
{
//Do some work
}
The tough part here is that ActionFilters seem to get instantiated new with each request and in a context that is outside of where Spring is aware. I handled the same situations using the Spring "ContextRegistry" class in my ActionFilter constructor. Unfortunately it introduces Spring specific API usage into your code, which is a good practice to avoid, if possible.
Here's what my constructor looks like:
public MyAttribute()
{
CustomHelper = ContextRegistry.GetContext().GetObject("CustomHelper") as IConfigHelper;
}
Keep in mind that if you are loading multiple Spring contexts, you will need to specify which context you want in the GetContext(...) method.

Resources