I am updating my wcf service reference through SvcUtil.exe.
command is as follows:
SvcUtil.exe http://localhost:50886/Service1.svc /n:*,ClassLibrary2.ServiceReference1 /o:Service References\ServiceReference1\Reference.cs /ct:System.Collections.Generic.List`1, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 /config:app.config
And my wcf code is as follows:
==============================================================
namespace WcfService1
{
[ServiceContract]
[ServiceKnownType(typeof(Dictionary<string, string>))]
public interface **IService1**
{
[OperationContract]
string GetData(int value);
// TODO: Add your service operations here
[OperationContract]
string Hello(string value);
}
}
namespace WcfService1
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public string Hello(string value)
{
return string.Format("You entered: {0}", value);
}
}
}
I am using this service in my class library project which name is ClassLibrary1. When i am updating this service through visual studio then in Reference.cs I got following statement:
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="**ServiceReference1.IService1**")]
public interface IService1
But when m updating service through svcutil then I got following statement:
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="**ClassLibrary2.ServiceReference1.IService1**")]
public interface IService1
The difference is configuration name. I didn't understand which command should i used in svcutil to set configuration name just as ServiceReference1.IService1 ?
Please help.
Just by changing [ServiceContract] into [ServiceContract(Name="ServiceReference1.IService1", ConfigurationName="ServiceReference1.IService1")]. See this block post.
Related
I am using blazor web assembly hosted. In Project.Client, I have the following files under data folder.
myProject.Client/Data/SQLConnConfig.cs:
public class SQLConnConfig
{
public string Value { get; }
public SQLConnConfig(string value) => Value = value;
}
myProject.Client/Data/MyService.cs:
public class MyService
{
public static SQLConnConfig _conn;
public SqlConnection connection;
public MyService(SQLConnConfig conn)
{
_conn = conn;
connection = new SqlConnection(_conn.Value);
}
public List<Item> GetItem()
{
......
}
myProject.Client/Data/Item.cs:
public class Item
{
[Key]
public string Id { get; set; }
public string Name{ get; set; }
}
Registered service in MyProject.Client/program.js
builder.Services.AddScoped<MyService>();
In myProject.Server/startup.cs:
var sqlConnConfig = new SQLConnConfig(Configuration.GetConnectionString("DefaultConnection"));
services.AddSingleton<SQLConnConfig>(sp => sqlConnConfig);
services.AddServerSideBlazor(x => x.DetailedErrors = true);
services.AddSingleton<MyService>();
App setting has connection string included.
In the index.razor: I inject and use the service.
#inject MyService MyService
protected override async Task OnInitializedAsync()
{
result = MyService.GetItem();
}
I get an error saying "Unhandled exception rendering component: Unable to resolve service for type 'System.String' while attempting to activate 'MyProject.Client.Data.SQLConnConfig". May I know where I am going wrong. Thank you.
Provide your SQLConnConfig class like this:
var sqlConnConfig = new SQLConnConfig(Configuration.GetConnectionString("DefaultConnection"));
builder.Services.AddScoped<SQLConnConfig>(sp => sqlConnConfig );
No need for static in public static SQLConnConfig _conn;
The error is coming from injection trying to construct the SQLConnConfig class.
i'm getting below error
Unable to resolve service for type 'System.Action1[DatabaseConsumer.MyFooClass]' while attempting to activate 'DatabaseConsumer.DatabaseScheduler1[DatabaseConsumer.MyFooClass]'.
My Service class looks like below example, I need to have Action action, TType objTType, string cron in the constructor as well, also, FooService implements IHostedService
public class DatabaseScheduler<TType> : FooService
{
protected override string CronSchedule { get; set; }
private Action<TType> _action;
TType _obj;
public DatabaseScheduler(IServiceScopeFactory serviceScopeFactory, Action<TType> action, TType objTType, string cron) : base(serviceScopeFactory, cron)
{
_action = action;
CronSchedule = cron;
_obj = objTType;
}
public override Task ProcessInScopeService(IServiceProvider serviceProvider)
{
//Call the ProcessIntegrationMessages()
_action.Invoke(_obj);
return Task.CompletedTask;
}
}
In the Startup.cs added my service class to IServiceCollection services
services.AddSingleton(typeof(Microsoft.Extensions.Hosting.IHostedService), typeof(DatabaseScheduler<MyFooClass>));
I have a unit of work with the repository pattern with simple injector implemented and I need to change my connection string dynamically. Currently the connection string is taken from the web config. I need the connection string be taken from the database.
So I will have a database with the ASP.Net Identity and the connections strings (and other configurations needed for my application) and then a database depending on the client.
My repositories and Unit of work are as follows.
public abstract class DataRepositoryBase<TEntity, TContext> : IDataRepository<TEntity>
where TEntity : class, IObjectStateEntity, new()
where TContext : class, IDbSimpleContextAsync
{
protected DataRepositoryBase(TContext context)
{
Context = context;
}
public virtual TContext Context { get; }
public IEnumerable<TEntity> Get()
{
return Context.Get<TEntity>();
}
public TEntity Get(object id)
{
return Context.Find<TEntity>(id);
}
}
public class SomeRepository : DataRepositoryBase<SomeObject, IContext>, ISomeRepository
{
public SomeRepository (IContext context) : base(context)
{
}
}
public abstract class UnitOfWorkBase : IUnitOfWork
{
private IDbSimpleContextAsync _dbContext;
protected UnitOfWorkBase(IDbSimpleContextAsync dbContext)
{
_dbContext = dbContext;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
public Task<int> SaveChangesAsync()
{
return _dbContext.SaveChangesAsync();
}
}
public class UnitOfWork : UnitOfWorkBase, IUnitOfWork
{
private ISomeRepository _someRepository
private readonly IContext _dbContext;
public UnitOfWork(IContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
}
public ISomeRepository SomeRepository => _someRepository ?? (_someRepository = new SomeRepository(_dbContext));
}
public class BookingBusiness : IBookingBusiness
{
protected IAllotmentUnitOfWork UnitOfWork { get; }
public AllotmentBusinessBase(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
...
business methods here
...
}
So my idea is when reaching business, I query the configuration database for the connection string for the current user (the current unit of work injected points to that database), and somehow use that connection to instantiate a new unit of work for to connect to the correct database. Any ideas how i can achieve this using my current setup?
You should prevent injecting objects into the object graph that change based on runtime information. The question here is whether or not the connection string is still a constant value (won't change after the application started), or can change from request to request (for instance, when each user gets its own connection string).
In case the connection string is a constant, the solution is simple: Just request the connection string at start-up and use it indefinitely, just as you already are doing currently.
If your connection string isn't a constant value from the config file, but runtime information, it and its consuming DbContext should not be injected anymore directly into the object graph. Instead, you should define an abstraction that allows requesting the correct DbContext based on runtime information, such as logged in user.
So instead of injecting an IContext into SomeRepository and UnitOfWork, inject an IContextProvider, which can be defined as follows:
public interface IContextProvider
{
IContext Context { get; }
}
Your DataRepositoryBase can use IContextProvider as follows:
public IEnumerable<TEntity> Get()
{
return this.contextProvider.Context.Get<TEntity>();
}
public TEntity Get(object id)
{
return this.contextProvider.Context.Find<TEntity>(id);
}
The part left is to define an implementation for IContextProvider that can load the right connection string from the database, and create and cache a DbContext based on that connection string. Considering the limited amount of information given, this is only something you will know how to do.
I have part of WebAPI application that I want to move to separate project as class library.
It is common base structure that almost every app has so idea is to make it easy shareable.
Application type is:
ASP.NET Core Web Application / .NET Framework - ASP.NET Core 2.0 / Web API
What I have done in that direction is created a project named Core and moved those shared elements there, including Base Entities (e.g. User, Settings, etc), CoreContext, UnitOfWork, Generic Repository, BaseRepositories,...
In the Main project of app there are others Entities, AppContext that inherits CoreContext, more Repositories, and all Controllers, ...
I was able to build the app but when starting it get the following error:
InvalidOperationException: Unable to resolve service for type 'Core.Data.CoreContext' while attempting to activate 'Core.Data.Repositories.UnitOfWork'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type
serviceType, Type implementationType, ISet callSiteChain,
ParameterInfo[] parameters, bool throwIfCallSiteNotFound)...
Problem seems to be that UnitOfWork class is in Core project and in Main project is Startup.cs with method ConfigureServices that has services.AddTransient<IUnitOfWork, UnitOfWork>();.
Is this a bug or am I just not configuring it correctly and how could it be achieved, if possible at all?
*Further technical details:
NetCore & EF Core version: 2.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
IDE: Visual Studio 2017 15.3
Operating system: Windows 10
UPDATE: Code Sample
namespace Main
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build();
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddMvc();
var conn = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<AppContext>(options => options.UseSqlServer(conn));
}
}
}
namespace Main.Data
{
public class AppContext : CoreContext
{
...
}
}
-
namespace Core.Data
{
public class UnitOfWork : IUnitOfWork, IDisposable
{
public CoreContext context;
public UnitOfWork(CoreContext context)
{
this.context = context;
}
public T Get<T>() where T : BaseRepository, new()
{
var repository = new T();
repository.Init(context);
return repository;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
public class UnitOfWork<TContext> : IUnitOfWork, IDisposable
where TContext : CoreContext
{
public UnitOfWork(TContext ctx) { ... }
...
}
-
public class AppUnitOfWork : UnitOfWork<AppContext> {
public AppUnitOfWork(AppContext ctx) : base(ctx) { }
}
...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IUnitOfWork, AppUnitOfWork>(); // Note the App prefix
services.AddDbContext<AppContext>(options => options.UseSqlServer(conn)); // Note the App prefix
}
...
}
Solution is from GitHub issue:
I have two interfaces that says if a service have to be singleton or transient:
public interface ITransient {}
public interface ISingleton {}
I implement this interfaces in other interfaces and classes:
public interface ISession : ISingleton
{
int? UserId {get;set;}
}
public class Session : ISession
{
public int? UserId {get;set;}
}
Then I inject Session in others services:
public interface IBookService : ITransient
{
...
}
public class BookService : IBookService
{
public BookService(ISession session) { ... }
...
}
How to configure StructureMap to make that all instance requests of types that implements ISingleton have to create with Singleton lifecycle??
I have tried it:
Container.Configure(conf => {
conf.For<ITransient>().Transient();
conf.For<ISingleton>().Singleton();
}
But nothing ... don't work, create a Session object as Transient.
I have tried it too:
Container.Configure(conf =>
{
conf.Scan(s =>
{
s.Assembly(assembly);
s.LookForRegistries();
s.AddAllTypesOf<ISingletonDependency>();
s.AddAllTypesOf<ITransientDependency>();
});
conf.For<ITransientDependency>().Transient();
conf.For<ISingletonDependency>().Singleton();
});
And nothing ...
I have seen how to do it using Windsor Castle:
context.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ITransient>()
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
//Singleton
context.IocContainer.Register(
Classes.FromAssembly(context.Assembly)
.IncludeNonPublicTypes()
.BasedOn<ISingleton>()
.WithService.Self()
.WithService.DefaultInterfaces()
.LifestyleSingleton()
But I don't know how to do using StructureMap ...
Other posibility is using conventions (IRegistrationConvention), but I don't know how to do, example:
public class LifecycleConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.GetInterface(typeOf(ISingleton) != null)
**???? what to do ??!!**
}
}
Somebody can help me please?
UPDATE
I have build a convention:
public class BasicConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (!type.IsAbstract && typeof(ISingleton).IsAssignableFrom(type))
{
registry.For(type, new SingletonLifecycle());
}
if (!type.IsAbstract && typeof(ITransient).IsAssignableFrom(type))
{
registry.For(type, new TransientLifecycle());
}
}
}
And that seem work but it register each class as plugin type, in this case:
Session => Session [Singleton]
BookService => BookService [Transient]
But if I inject the Session as ISession ... don't found the instance due to ISession is not registered ... But I can use default convetions ... and then work BUT retrieve the instance as transient ...
Calling WhatDoIHave() I can see it:
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
....
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Transient Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') Paf.Application.Session,... (Default)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
.....
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Session Paf.Application Singleton Paf.Application.Session (Default)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
...
===============================================================================================================================================================================================================================================================================
Can I solve this it?
Ok, I have gone to StructureMap sources to see how to work the default contention.
I found DefaultConventionScanner class:
public class DefaultConventionScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!type.IsConcrete()) return;
var pluginType = FindPluginType(type);
if (pluginType != null && type.HasConstructors())
{
registry.AddType(pluginType, type);
ConfigureFamily(registry.For(pluginType));
}
}
public virtual Type FindPluginType(Type concreteType)
{
var interfaceName = "I" + concreteType.Name;
return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
}
}
I can deduce that I could change the plugin type registration (registry.AddType(pluginType, type) line of code) and write it:
if(typeof(ISingleton).IsAssignableFrom(type))
registry.For(pluginType).Use(type).Singleton();
else if (typeof(ITransient).IsAssignableFrom(type))
registry.For(pluginType).Use(type).Transient();
else
{
registry.AddType(pluginType, type);
}
ConfigureFamily(registry.For(pluginType));
Ergo, if the pluginType (interface type) is ISingleton or ITransient I registry the new plugin type as Singleton or Transient otherwise registry the pluginType as allwais.
I have try and know work!! yeah!
Only one consideration, I don't know if exists some diference between:
registry.AddType(pluginType, type);
and:
registry.For(pluginType).Use(type);
I have compare the results of WhaDoIHave() before and after, and I can see a only one difference.
Old result:
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Transient Paf.Application.Session ('Paf.Application.Session, Paf.Modules.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') Paf.Application.Session,... (Default)
===============================================================================================================================================================================================================================================================================
New result:
===============================================================================================================================================================================================================================================================================
PluginType Namespace Lifecycle Description Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ISession Paf.Application.Session Singleton Paf.Application.Session (Default)
===============================================================================================================================================================================================================================================================================
The new result is Ok, is Singleton, the diference is only in description, I think is no important think.
UPDATE
According to conversation with Steve in the comments of my question, I have decide not use ITransient and ISingleton interfaces. I have decided to use Attributes in the implementation classes.
I've created 2 attributes:
[AttributeUsage(AttributeTargets.Class)]
public class SingletonLifecycleAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class)]
public class TransientLifecycleAttribute : Attribute
{
}
And I've assiged its to my classes:
public interface ISession { int? UserId {get;set;} }
[SingletonLifecycle]
public class Session : ISession { public int? UserId {get;set;} }
public interface IBookService { ... }
[TransientLifecycle]
public class BookService : IBookService { public BookService(ISession session) { ... } }
Then I have modified my convention:
public class BasicConvention : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!type.IsConcrete()) return;
var pluginType = FindPluginType(type);
if (pluginType != null && type.HasConstructors())
{
var ci = registry.For(pluginType).Use(type);
if (type.GetCustomAttributes(true).FirstOrDefault(a => a is TransientLifecycleAttribute) != null)
ci.Transient();
if (type.GetCustomAttributes(true).FirstOrDefault(a => a is SingletonLifecycleAttribute) != null)
ci.Singleton();
ConfigureFamily(registry.For(pluginType));
}
}
public virtual Type FindPluginType(Type concreteType)
{
var interfaceName = "I" + concreteType.Name;
return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
}
}
I think all is now fine and better ;)
Thanks Steve!