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;
}
Related
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 >(), "" ));
Given the following:
public class Parent
{
public ChildType childType;
}
public class ChildA : Parent { ... }
public class ChildB : Parent { ... }
public enum ChildType {
childA,
childB
}
public class Content {
public long contentId;
public string? name;
public ICollection<Parent>? contentCollection; <--
...
}
I would like to use the Content class as part of an API. Is it possible to load both children into the collection just using the enum as a discriminator to determine which to cast to?
My understanding is the child objects would need to be loaded from EF as their child class first, then cast to the parent class before being added to the collection as they would be missing properties upon casting back to the child class otherwise. Is this correct? And how can the dbContext be configured to handle this when accessing through the Content class?
Apologies for all the questions, I have not done this before and cannot find an example online. I would like to know any thoughts, pointers or general info before proceeding. Please say if anything is unclear or more info is required.
Edit:
I was trying to map the child objects as their types from the DB, upcast to the parent type to be able to add multiple types to the one collection and then downcast when required for use. As far as I was aware, EF did not have the functionality to do this.
For anyone else who comes across this which needs assistance, I solved my issue by just using ADO.NET which is what entity framework is built around. I was getting stuck by trying to get this working using EF but my belief is it is not able to be done with EF.
Formatting is off a little, and I have renamed everything to suit my original question but here is the solution involved:
Writing an SP to retrieve the data similar to if the objects were stored in a TPH pattern.
Calling that SP using SQLConnection/SQLCommand. (I added this into my context class to keep DAL together but unsure if this is best practice)
public async Task<Collection<Parent>> GetModelMapCollectionAsync(long id) {
Collection<Parent> parentCollection;
using (SqlConnection connection = new SqlConnection(this.Database.GetConnectionString()))
{
using (SqlCommand sqlCommand = new SqlCommand("GetModelMapCollectionAsync", connection))
{
sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
sqlCommand.Parameters.Add(new SqlParameter("#id", id));
await connection.OpenAsync();
await sqlCommand.ExecuteNonQueryAsync();
using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync())
{
MapCollectionResult(sqlDataReader, out parentCollection);
}
}
}
return parentCollection; }
Using a nuget package called Dapper, create row parsers for each type (easiest solution for readability/simplicity IMO)
Use the discriminator column to determine which parser to use on each row returned from the SP. This creates the child object from the row which allows it to be downcast back later.
Add that parsed object to the collection.
private void MapCollectionResult(SqlDataReader sqlDataReader, out Collection parentCollection)
{
parentCollection= new Collection();
var parentParser = sqlDataReader.GetRowParser<Parent>(typeof(Parent));
var paramClassParser = sqlDataReader.GetRowParser<ParamClass>(typeof(ParamClass));
var childAParser = sqlDataReader.GetRowParser<ChildA>(typeof(ChildA));
var childBParser = sqlDataReader.GetRowParser<ChildB>(typeof(ChildB));
ChildType type = ChildType.None;
Parent parent;
while (sqlDataReader.Read())
{
type = (ChildType)sqlDataReader["ChildTypeId"];
switch(type)
{
case ChildType.ChildA:
parent = childAParser(sqlDataReader);
break;
case ChildType.ChildB:
parent = childBParser(sqlDataReader);
break;
default:
parent = parentParser(sqlDataReader);
break;
}
parent.paramClass = paramClassParser(sqlDataReader);
parentCollection.Add(parent);
}}
Hey Guys i'm very new in software development,I still no idea when to use which,whats the meaning of service lifetime!it may seem stupid but please help me,i have an interface :
public interface IAccessInfo
{
public IEnumerable<AccessInfo> getResult();
}
what it supposed to do is to returns me the information about my Turbines;here is the implementation of it :
public class AcessInfoData:IAccessInfo
{
private DbContextClass db;
public AcessInfoData(DbContextClass context)
{
db = context;
}
public IEnumerable<AccessInfo> getResult()
{
var turbines = (from c in db.accessinf
where s.user_id == "i0004912"
select new AccessInfo
{
InfoType = c.type,
TurbineId = c.m_plc_id.ToString(),
TurbineIP = c.turbine_ip.ToString(),
TurbineIdSorting = c.turbine_id,
Blade = c.blade,
Certification = c.certification,
}).Distinct();
return turbines;
}
}
it gets an instance of my DB and gets the data;and in my controller i use it like this:
public class AcessInfoController : ControllerBase
{
private IAccessInfo _acess;
public AcessInfoController(IAccessInfo access)
{
_acess = access;
}
[HttpGet]
public IActionResult Index()
{
var rsult = _acess.getResult();
return Ok( rsult);
}
}
now in the Startup i registered it :
services.AddScoped<IAccessInfo, AcessInfoData>();
it works,but if you sk me why i user Scoped and not Singleton or transient i have no idea why,really,any one can make it clear for me?
I will try to explain a little about the mentioned cases:
scoped : For all needs of an object during the life of an operation (such as a request from the client) a single instance of the object is created. (It means that only one instance of the object is sent for all requirements during life time of a request)
Singleton: Creates only one instance of object and sends it for all requirements in the application scope.(For all needs everywhere in the program, only one instance of the object is sent, a bit like static objects).
Transient: Ioc container, makes an instance of object whenever code needs it, that is, it makes an instance for each requirement anywhere in the program and at any time, which means that if the program needs an object 3 times, it makes an independent instance for each.
Instance: In this case, each time an object is needed, only one instance of it is provided to the program, which you defined it in the startup section. (when defining it in the startup section, you specify how to create an instance).
I hope to reduce some of the ambiguities.
I created a database in Azure setting my own custom name. I then created EF 5 code first entities and added migrations. On application startup I called these two lines:
Database.DefaultConnectionFactory = new SqlConnectionFactory(connectionString);
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, MyConfiguration>());
Connection string is taken straight from Azure:
Server=tcp:xxx.database.windows.net,1433;Database=dbName;User ID=yyy;Password=zzz;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;
On fist call I expected database dbName to be filled with tables according to POCO schema.
But instead a NEW database is generated with the complete namespace name of my context:
MyService.Business.Entity.MyContext
Why will the migration not accept the database name specified in the connection string?
You can specify the Database name or connection string name in the constructor of your DbContext:
public class MyDataContext : DbContext
{
public MyDataContext: base("DbNameOrConntectionStringNameHere")
{
}
}
My experience is that, in the case where the connection string is being passed in code, rather than obtained from app.config, EF is quirky about how it obtains the connection string.
I had to add a class that inherited from IDBContectFactory
public class ContextFactory : IDbContextFactory<Context>
{
public Context Create()
{
var s = (string)AppDomain.CurrentDomain.GetData("ConnectionString");
var context = new Context(s);
return context;
}
}
Also, in order to create a migration, I needed the following in my context class
// uncomment when creating migration - comment out after migration is created
public Context() : base("ConnectionStringName"){}
Where the ConnectionStringName is set up in my app.config.
I am still mystified that I had to do this and have asked about it here
I created an Array of Object from the .Net environment as follows :
Dim names(2) As User
names(0) = New User("param1", "param2", "param3")
names(1) = New User("param1", "param2", "param3")
Here I have created a User class with 3 String variables. I also created a User class at Java environment with same String variables and the Java class accepts User[] user. I generated webservice based on the Java class and forwrading the parameter from the .Net environment as follows :
Dim MyService As localhost.ReadObject = New localhost.ReadObject
Dim resultString As String = MyService.ReadParameters(names)
i have done what you need. if you pass array object(list is not supported in WebService) then in java you need to use class which has an array type of variable then generate getter and setter of that array type of variable and then generate wsdl again.
if you do that then java service will accepts your array input.
suppose your service need to send "PurchaseOrder" kind of array object then say :
class OuterObject{
public PurchaseOrder[] order;
public PurchaseOrder[] getOrder() {
return order;
}
public PurchaseOrder[] setOrder( PurchaseOrder[] order) {
this.order = order;
}
}
then use OuterObject as input parameter in your service method.say:
class ServiceClass{
public placeOrder(OuterObject object){
PurchaseOrder[] data = object.getOrder();
int ordernumber = data.getOrderNumber();
System.out.println("ordernumber is = " + ordernumber);
}
}
it will work but use only array not list, service doesn't support list.