How to pass a runtime parameter as part of the dependency resolution for a generic class? - asp.net-core

A similar question has been answered here:
How can I pass a runtime parameter as part of the dependency resolution?
However, I was wondering how this can be done when registering a generic class?
Normally, I would register it as following:
services.AddScoped(typeof(ITest<>), typeof(Test<>));
But what if I want to pass a runtime parameter to constructor? Without using DI, it would be something like:
new Test<MyClass>(string mystring, int myInt)
In the linked answer it's suggests using a factory method but this is giving me an error if I don't pass it the exact type.
The alternative would be to get an instance without passing a runtime parameter in the constructor and instead using a setter method after getting exact instance. I would like to avoid this however because every time after getting instance you must remember to call setter method.
Is there some way around it? I guess I could use some factory class instead of registering it in startup class...
EDIT:
After reading Steven's answer which was very useful, I updated question with more concrete example:
Following example is inside some method:
//instance of repository are passed inside constructor of class
//calling some to update/insert
//IMPORTANT - calling external service I want save parameters to db no matter what
using(var ctx=new DbContext())
{
//create log object
ctx.logs.add(Obj)
ctx.save()
}
//some code after
Let's say I want to be consistent and call method of my loggingrepository and there add logging object and save everything to database
However, every repository in constructor accepts DbContext, which is registered as scoped (durig one request).
If it's inside transaction, saving depends about code after calling external service and it can throw exception and save nothing.
So yeah, I could create new dbContext and pass it in logging method or call some private logging function and save inside it,
but point is that if I would ask for instance of loggingRepository I would want DI to pass this localy created dbContext variable to constructor
and not one registered as scoped inside startup method, so that addind and saving log happens no matter what external service or code after calling it does.
My situation in something similar, but it's going for some data in db based on current user and I don't wanna pass same parameter to numerous method, but only inside class constructor.

The general solution in injecting primitive configuration values into your application components, is to extract them into a Parameter Object. This gives those values a new, unambiguous type, which can be registered into your container:
// Parameter Object
public TestConfiguration
{
public string Mystring;
public int MyInt;
}
// (Generic) class using the Parameter Object
public class Test<T>
{
public Test(TestConfiguration config) { ... }
}
// Registering both
services.AddScoped(typeof(ITest<>), typeof(Test<>));
services.AddSingleton(new TestConfiguration { Mystring = ..., Myint = ... });
Configuration values are not considered to be runtime data as their values are known at startup and constant for the duration of the application. That's why you can supply them to the constructors of your application components.
Real runtime data, however, should not be passed on to a component during construction. Runtime data are values that are not known at startup and typically passed along by the user through a web request, are retrieved from the database, session, or anything that can change during the lifetime of the application.
Instead of passing runtime data in through the constructor, you should either:
Pass runtime data through method calls of the API or
Retrieve runtime data from specific abstractions that allow resolving runtime data.
You can find more information about passing runtime data here.

Related

Ninject - Resolve instance per method call

I'm finding a solution to resolve an instance per method call.
Something like that:
public class ServiceAPI
{
public void ServiceAction()
{
//Call certain repository action
// Ex:
Kernel.Get<RepositoryA>().Insert();
}
}
public class RepositoryA
{
public void Insert(object a)
{
//Get logger per service call ?
var logger = Kernel.Get<RepositoryA>().Insert();
}
}
I wanna the logger instance created one time per service call and it will be used throughout the repository.
I try with Ninject.Extensions.NamedScope extensions but it haven't worked yet.
Can you have any way to deal with this scenario ?
It is not possible to achieve this by using a scoping mechanism. (InCallScope(), InNamedScope(...),...).
Scoping is only relevant when ninject is calling the constructor of a type.
Ninject cannot - ever - replace the instance that is already passed to an object.
If you want to do this you have to program it yourself.
Here's two design alternatives how you can achieve what you want:
instantiate an object tree per method invocation. If there's some service infrastructure like WCF or Web-API there are probably hooks which can be used to do so.
replace the object which should be instantiated per method call by a proxy. The proxy can then use Ninject to create the target for each method call and execute the method on it.
For proxying you can use tools like Castle DynamicProxy or LinFu. There's also Ninject.Extensions.Interception which may also be helpful.

Sencha Touch: perform read (load) operation from singleton model

I have a singleton model and an associated AJAX proxy.
If I make a call to MyModel.load(), I get the error:
MyModel.load is not a function
However, you do have load in Model:
http://docs.sencha.com/touch/2.4/2.4.1-apidocs/#!/api/Ext.data.Model-static-method-load
On the contrary, MyModel.save() exists and I can access it.
Is this a bug or am I missing something?
The load method listed on Ext.data.Model is a static method on the class definition, not an instance. The documentation even denotes this is a static method. When you want to load a record, you don't load an already instantiated record, you load the model definition and that loading creates an instance.
The save method listed on Ext.data.Model is an instance method, the docs do not denote this as a static method. You don't save a class definition, you save an instance.
Example usage: https://fiddle.sencha.com/#fiddle/lvj

Subtype of shared data contract

Following advices from people on the internet about service references, I got rid of them now and split the service/data contracts into a common assembly accesible by both the server and the client. Overall this seems to work really well.
However I’m running into problems when trying to use custom objects, or rather custom subtypes, in the service. Initially I wanted to define only interfaces in the common assembly as the contract for the data. I quickly learned that this won’t work though because the client needs a concrete class to instantiate objects when receiving objects from the service. So instead I used a simple class instead, basically like this:
// (defined in the common assembly)
public class TestObject
{
public string Value { get; set; }
}
Then in the service contract (interface), I have a method that returns such an object.
Now if I simply create such an object in the service implementation and return it, it works just fine. However I want to define a subtype of it in the service (or the underlying business logic), that defines a few more things (for example methods for database access, or just some methods that work on the objects).
So for simplicity, the subtype looks like this:
// (defined on the server)
public class DbTestObject : TestObject
{
public string Value { get; set; }
public DbTestObject(string val)
{
Value = val;
}
}
And in the service, instead of creating a TestObject, I create the subtype and return it:
public TestObject GetTestObject()
{
return new DbTestObject("foobar");
}
If I run this now, and make the client call GetTestObject, then I immediately get a CommunicationException with the following error text: “The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:09:59.9380000'.”
I already found out, that the reason for this is that the client does not know how to deserialize the DbTestObject. One solution would be to declare the base type with the KnownTypeAttribute to make it know about the subtype. But that would require the subtype to be moved into the common assembly, which is of course something I want to avoid, as I want the logic separated from the client.
Is there a way to tell the client to only use the TestObject type for deserialization; or would the solution for this be to use data transfer objects anyway?
As #Sixto Saez has pointed out, inheritance and WCF don't tend to go together very well. The reason is that inheritance belongs very much to the OO world and not the messaging passing world.
Having said that, if you are in control of both ends of the service, KnownType permits you to escape the constraints of message passing and leverage the benefits of inheritance. To avoid taking the dependency you can utilise the ability of the KnownTypeAttribute to take a method name, rather than a type parameter. This allows you to dynamically specify the known types at run time.
E.g.
[KnownType("GetKnownTestObjects")]
[DataContract]
public class TestObject
{
[DataMember]
public string Value { get; set; }
public static IEnumerable<Type> GetKnownTestObjects()
{
return Registry.GetKnown<TestObject>();
}
}
Using this technique, you can effectively invert the dependency.
Registry is a simple class that allows other assemblies to register types at run-time as being subtypes of the specified base class. This task can be performed when the application bootstraps itself and if you wish can be done, for instance, by reflecting across the types in the assembly(ies) containing your subtypes.
This achieves your goal of allowing subtypes to be handled correctly without the TestObject assembly needing to take a reference on the subtype assembly(ies).
I have used this technique successfully in 'closed loop' applications where both the client and server are controlled. You should note that this technique is a little slower because calls to your GetKnownTestObjects method have to be made repeatedly at both ends while serialising/deserialising. However, if you're prepared to live with this slight downside it is a fairly clean way of providing generic web services using WCF. It also eliminates the need for all those 'KnownTypeAttributes' specifying actual types.

JEE6 application session scoped objects

I'm still pretty new to JEE6 having come from a Servlets + JSP style of development on legacy systems. In the applications I worked on we would just throw objects into the various supplied scopes (request, session and application) keyed on a constant String. For example, the User object that represented the currently logged in user would be in the session scope keyed under "current_user".
I've done the same in our new JEE6 application, when the user logs in the User object is bound into the session scope. I'm wondering though if there is a better, more EE, way of handling this?
The problem I'm having is that now I've got the User stored in the session it's awkward to get access to it again. I can get it via JNDI look up or with a few lines of boiler plate code involving FacesContext but neither are very elegant.
Rather than boiler plate code all over the place (the User object is need in a few places) it would be great if I could just get the object injected into a field or method. After all there can only be one object in the session bound to a particular name so there shouldn't be any ambiguity about what I'm asking for. Is this possible?
Maybe the CDI could be of any help?
Could you define the way you achieve the User object into one, main method?
If so, and you're working with Java EE 6 environment, you could use the Producer method. Something between these lines:
public class ClassWhichCanAccessUserObject {
#Produces
public User produceUser() {
User u = ... // get the user as you do it right now
return u;
}
}
Then in the place you want to use this class you just Inject it (in the field or method) and use it:
public class MyLogic {
#Inject
User u;
}
You need to remember to add the beans.xml file to your classpath, as without the CDI will not work for your module.

MEF Property Export with PartCreationPolicy

When I try to do this:
[Export(typeof(IMyService))]
[PartCreationPolicy(CreationPolicy.Shared)]
private MyService Service
{
get
{
var service = new MyService();
service.Configure();
return service;
}
}
I get a compile error: Attribute 'PartCreationPolicy' is not valid on this declaration type. It is only valid on 'class' declarations.
Is this a bug? I don't see why MEF would allow property exports but not allow one to specify the part lifetime.
Using VS2010 RC.
The PartCreationPolicy should go on the class, even if the export goes on the property. The class is what corresponds to the part, and the creation policy will control whether MEF creates a new instance of the class each time an export is requested from it or not.
I am not sure whether you want to use Shared or NonShared. You have the CreationPolicy set to Shared in your code example, but then you are creating a new instance of MyService in your property getter. That seems to indicate you may be looking for a creation policy of NonShared.
If you do want a new service to be created each time an export is requested, you should do it via the creation policy, and not by creating a new instance in the getter. The value of an export is not supposed to change at runtime, and in fact MEF will only call the getter once, and store the return value for when it needs to access the exported value again. So creating a new instance in your getter can make it look like there would be multiple services created when there will actually only be one.