Having the following service constructor
public class Service : IService
{
public Service(IOtherService service1, IAnotherOne service2, string arg)
{
}
}
What are the choices of passing the parameters using .NET Core IOC mechanism
services.AddSingleton<IOtherService , OtherService>();
services.AddSingleton<IAnotherOne , AnotherOne>();
services.AddSingleton<IService>(x =>
new Service(
services.BuildServiceProvider().GetService<IOtherService>(),
services.BuildServiceProvider().GetService<IAnotherOne >(),
""));
Is there any other way ?
The expression parameter (x in this case) of the factory delegate is an IServiceProvider.
Use that to resolve the dependencies:
_serviceCollection.AddSingleton<IService>(x =>
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));
The factory delegate is a delayed invocation. Whenever the type is to be resolved, it will pass the completed provider as the delegate parameter.
The recommended way to achieve this is to use the Options pattern - note that this applies to any .NET Core/5 application, not just ASP.NET Core. But there are use cases where it's impractical (e.g. when parameters are only known at runtime, not at startup/compile-time) or you need to dynamically replace a dependency.
It's very useful when you need to replace a single dependency (be it a string, integer or another type of dependency) or when using a 3rd-party library which accepts only string/integer parameters and you require runtime parameters.
You could try ActivatorUtilities.CreateInstance<T>(IServiceProvider, Object[]) as a shortcut rather than resolving every single dependency manually:
_serviceCollection.AddSingleton<IService>(x =>
ActivatorUtilities.CreateInstance<Service>(x, "");
);
The parameters to pass to your service's constructor (the object[] parameter to CreateInstance<T>/CreateInstance) allows you to specify parameters that should be injected directly, as opposed to resolved from the service provider. They are applied from left to right as they appear (i.e. first string will be replaced with the first string-typed parameter of the type to be instantiated).
ActivatorUtilities.CreateInstance<Service> is used in many places to resolve service and replace one of the default registrations for this single activation.
For example, if you have a class named MyService, and it has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say it's OtherServiceA) with OtherServiceB, you could do something like:
myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider,
new OtherServiceB());
Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA - but the remaining parameters will come from the service provider.
This is helpful when you have many dependencies and want just to treat a single one specially (i.e. replace a database-specific provider with a value configured during the request or for a specific user, something you only know at runtime and/or during a request - not when the application is built/started).
If performance is a concern, you can use ActivatorUtilities.CreateFactory(Type, Type[]) to create a factory method instead. GitHub reference and benchmark.
This is useful when the type is resolved very frequently (such as in SignalR and other high request scenarios). Basically, you'd create an ObjectFactory via
var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new Type[] { typeof(IOtherService), });
then cache it (as a variable etc.) and invoke it where needed:
MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);
This all works perfectly with primitive types too - here's an example I tested with:
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));
var provider = services.BuildServiceProvider();
var demoService = provider.GetRequiredService<DemoService>();
Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}
public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;
public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}
public string HelloWorld()
{
return this.helloWorldService.Hello(firstname, lastname);
}
}
public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}
// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object[] parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}
Prints
Output: Hello Tseng Stackoverflow
If you feel uncomfortable with newing the service, you could use the Parameter Object pattern.
So extract the string parameter into its own type
public class ServiceArgs
{
public string Arg1 {get; set;}
}
And the constructor will now look like
public Service(IOtherService service1,
IAnotherOne service2,
ServiceArgs args)
{
}
And the setup
_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();
The first benefit is if you need to change the Service constructor and add new services to it, then you don't have to change the new Service(... calls. Another benefit is the setup is a bit cleaner.
For a constructor with a single parameter or two, this might be too much though.
You can inject dependencies with this process also
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService>(x=>new Service( x.GetService<IOtherService>(), x.GetService<IAnotherOne >(), "" ));
I am trying to serialize some JSON input to a data contract in Microsoft Dynamics 365 Finance. A simple data contract class works fine, but I cannot get data contract extensions to work. Does any one have experience with this or perhaps a working example?
The only related information I managed to find on this topic comes from this forum post.
Follow some hyperlinks and you will end up with the official Microsoft documentation (Ref# 199219), which states that this should be supported.
All variations of the data contract attributes below compile fine, but proved unsuccessful for me:
Using DataContract and DataMember instead of DataContractAttribute and DataMemberAttribute.
Combining DataContract and DataContractAttribute on a single method. (Produces runtime error about double serialization attribute.)
Repeating the DataContractAttribute on the extension class.
Additional experiments with the JSON deserializer class through its various constructor options also proved unsuccessful:
Passing a list of known types ClassA and ClassA_Extension.
Passing a list of known types ClassA_Extension and ClassA (in case the list order had an impact).
Passing a settings object and explicitly setting IgnoreExtensionDataObject to false (this appears to be the default).
Passing the extension class type as first parameter.
Update
A ticket was raised with Microsoft to investigate the issue. In their response they mentioned that they were able to reproduce this. They also declared that this was "by design" and "will not be fixed".
Our final solution will most likely be the following:
Build a mapping of DataMemberAttribute values and the corresponding data contract method.
Use a JavaScriptSerializer object to turn the JSON into a nested .NET dictionary object.
Iterate over the dictionary object and populate the data contract with the help of the mapping.
Example
Below is a miminal example to demonstrate my issue. The values of the variables value1 and value2 are populated as expected, but variable value3 remains empty.
Data contract
[DataContractAttribute('Class A')]
public class ClassA
{
protected str value1;
protected str value2;
[DataMemberAttribute('Value1')]
public str value1(str _value1 = value1)
{
value1 = _value1;
return value1;
}
[DataMemberAttribute('Value2')]
public str value2(str _value2 = value2)
{
value2 = _value2;
return value2;
}
}
Data contract extension
[ExtensionOf(classStr(ClassA))]
public final class ClassA_Extension
{
private str value3;
[DataMemberAttribute('Value3')]
public str value3(str _value3 = value3)
{
value3 = _value3;
return value3;
}
}
Serialization code with hard-coded input
public class ClassTest
{
public static void main(Args _args)
{
str inputJSON = #'{
"Value1": "abc",
"Value2": "def",
"Value3": "ghi"
}';
ClassA ret = new ClassA();
System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding::UTF8.GetBytes(inputJSON));
System.Runtime.Serialization.Json.DataContractJsonSerializer dcjSer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(ret.GetType());
ret = dcjSer.ReadObject(ms);
ms.Close();
}
}
Result
It looks like the serializer is having issues. You might be able to pass a Type array similar to how FormRunConfigurationPropertyClassList does it?
I have at least two different classes like following :
//NOTE : these two classes have getter and setter also
class Artist {
String artistName;
String artistWebsite;
String artistDbpedia;
String artistImage;
List<String> astistAlbumsName;
List<String> astistAlbumsUrl;
}
class Venu {
String VenuName;
String VenuWebsite;
String VenuDbpdia;
String VenuImage;
String VenuDescription;
List<String> venuFans;
}
I want to have a producer class to get an xml file as an input and detect the type of xml (venu/artist) then start to create a product object based on the input.
the problem :
I want to create an interface for aggregate the similarity between above two classes so my interface would be:
interface Model {
public String getImage();
public String getName();
public String getWebsite();
public String getdbpedia();
}
Then I can implement this interface in my builder class and above two classes but how about those different methods?
such as getVenuFans / getArtistAlbumName / etc....?
How can I call them from my producer?
this is my builder :
Class Builder implements Model {
public String getImage(){}
public String getName(){}
public String getWebsite(){}
public String getdbpedia(){}
}
and this can be my producer :
Class Producer {
public Producer()
{
Builder b = null;
//assume Venu and Artist implements Model
b = (Builder) new Venu();
//I don't have access to getVenuFans()!
b = (Builder) new Artist();
//I don't have access to getArtistAlbumsName() / etc...
}
}
You don't have access to those methods because you're casting the objects to a Builder, and Builder doesn't have those methods.
I see what you're trying to do, but I don't think it will work. For example, getVenueFans (I'm assuming you mean venue) is only appropriate for the Venue class. It doesn't make sense to try and abstract that into an interface that other non-Venue classes will implement.
I think what you have is good: You've abstracted the common methods into an interface. To call the methods on Venue and Artist, the consuming code will need to cast the objects to the appropriate type, then call the methods on it. And that's not as bad as you might think. It's the consuming code that knows what type it's dealing with (otherwise, why would it be trying to call getVenueFans?), so that's the point where it makes sense to cast and call the method directly.
Is there any way to specify the return type for PexChoose at runtime? For example PexChoose.Value(name, Type)?
This would be useful to make general models that generate values of different types depending on runtime contraints.
You could build your own helper class which will call the generic version via reflection.
For instance, to create a non-generic version of PexChoose.Value(string name)
public static class MyPexChoose
{
public static object Value(Type myType, string name)
{
// Find the PexChoose.Value() method which has a single string parameter
MethodInfo method = typeof(PexChoose).GetMethod("Value", new Type[1] {typeof(string)});
// Make and invoke the generic version of it
MethodInfo generic = method.MakeGenericMethod(myType);
return generic.Invoke(typeof(PexChoose), new object[1] { name });
}
}
Then the call
MyPexChoose(typeof(DateTime), "MyChosen");
is equivalent to
PexChoose<DateTime>("MyChosen");
In one class I have defined the connection string like this
SqlConnectionStringBuilder objConnectionString = new SqlConnectionStringBuilder();
objConnectionString.DataSource = localServer; ;
objConnectionString.UserID = userName;
objConnectionString.Password = password;
objConnectionString.InitialCatalog = selectedDatabase;
where local server = txtHost;--DataSource
userName = txtUsername;
password = txtPassword;
But in my another project I want to access the controls of that project
Currently I am connected with the db like this
using(var sConnection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]))
But I want to make it such that it would take the value directly from the textboxes used in another project
Waiting for your suggestions .....Can It be done..
You will not bne abble to do this, unless you pass the actual controls to the method in the other project.
Why not rather pass the SqlConnectionStringBuilder object that you set up before hand to the method being called?
In your form with the textbox you will need to create Properties to access the values from the form, e.g.
public string Server
{
get
{
return this.txtHost.Text;
}
}
You will also need to pass a reference of the Form to your other Project, either by referencing the project, or using an shared interface between the two.
In your project where you want to build the connection string, you will need some way of receiving the reference to the Form, such as
public void RunMyQuery(MyForm form)
{
var objConnectionString = new SqlConnectionStringBuilder();
objConnectionString.DataSource = form.Server;
}
If you have time, consider creating a new project which contain shared interfaces, so you could create an interface such as
public interface IConnectionStringPartProvider
{
string Server { get; }
... other parts
}
and implement this interface on your form
public partial class Form1 : Form, IConnectionStringPartProvider
Then you would not need to reference you form project in your logic class, just let both projects reference the shared project.
This way, your query method could be replaced with
public void RunMyQuery(IConnectionStringPartProvider provider)
{
var objConnectionString = new SqlConnectionStringBuilder();
objConnectionString.DataSource = provider.Server;
}