我目前正在使用WebApiRequestLifestyle具有默认的范围生活方式.我想在OWIN中间件和其中一个API控制器中注入一个服务,服务的范围应该仍然是WebAPI,即对于整个请求,应该只有一个服务实例.
public class TestMiddleware : OwinMiddleware
{
private readonly ITestService _testService;
public TestMiddleware(OwinMiddleware next, ITestService testService) : base(next)
{
_testService = testService;
}
public override async Task Invoke(IOwinContext context)
{
var test = _testService.DoSomething();
await Next.Invoke(context);
}
}
public class ValuesController : ApiController
{
private readonly ITestService _testService;
public ValuesController(ITestService testService)
{
_testService = testService;
}
}
Run Code Online (Sandbox Code Playgroud)
整个请求的ITestService实例应该相同.我该如何注册中间件?
这就是我现在这样做的方式:
using (container.BeginExecutionContextScope())
{
var testService = container.GetInstance<ITestService>();
app.Use<TestMiddleware>(testService);
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是 - 在注册期间为中间件创建一个ITestService实例并永久保留(如单例),并且对于每个webapi请求,都会在控制器之间创建和共享新实例(webapi范围)
请不要指出这些问题 - WebApi + Simple Injector + OWIN
c# dependency-injection simple-injector asp.net-web-api owin
我在使用通用存储库实现 SimpleInjector 时遇到一些问题。
我有一个接口和一个实现该接口的IRepository<T> where T : class抽象类。abstract class Repository<C, T> : IRepository<T> where T : class where C : DbContext最后,我有了继承抽象类的实体存储库。这是一个具体的例子:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Remove(T entity);
}
public abstract class Repository<C, T> : IRepository<T>
where T : class where C : DbContext, new()
{
private C _context = new C();
public C Context
{
get { return _context; }
set { …Run Code Online (Sandbox Code Playgroud) 使用IoC可解析接口来指定DTO有什么价值吗?
Fer示例:
private readonly IGetTransactionsQuery _query;
private readonly ICreateTransactionCommand _createCommand;
public TransactionsController(
IGetTransactionsQuery query,
ICreateTransactionCommand createCommand)
{
_query = query;
_createCommand = createCommand;
}
[EnableQuery]
public IQueryable<ITransactionQueryModel> Get()
{
return _query.Execute();
}
public async Task<IHttpActionResult> Post(ICreateTransactionModel transaction)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _createCommand.Execute(transaction);
return Created(transaction);
}
Run Code Online (Sandbox Code Playgroud)
在这里,我使用的是ITransactionQueryModel和ICreateTransactionModel,而不是结核.这里有商业价值吗?哪种方案可以从这种方法中受益?我可以想到一些,但希望得到一些用例场景的共识
注意:我只是指控制器"动作"方法,而不是构造函数,因为IoC的好处是显而易见的
在我的应用程序中,我有许多服务,我使用以下模式:在与接口相同的文件中,我定义了一个静态工厂方法,该方法由IoC容器控制,如下所示:
public interface ISomethingService {
Task DoSomethingAsync(int id);
}
public class SomethingServicFactory : ServiceFactory<ISomethingService > { }
public class ServiceFactory<T>
{
public static Func<T> CreateClosure;
public T GetDefault() => CreateClosure();
}
Run Code Online (Sandbox Code Playgroud)
创建和配置IoC容器后:
SomethingServicFactory .CreateClosure = () =>
Container.GetInstance<ISomethingService >();
Run Code Online (Sandbox Code Playgroud)
稍后在我的应用程序中,当我需要SomethingService时:
var somethingService= new SomethingService().GetDefault();
Run Code Online (Sandbox Code Playgroud)
这允许我将创建推迟到最后一刻,但仍然使用容器控制服务创建.我刚开始使用SimpleInjector.更重要的是,它允许我创建服务实例并轻松传递参数,同时控制IoC.
这个模式帮助我的一个很好的例子是WPF XAML实例化的用户控件,它需要填充数据(即数据库中的查找值).在后面的代码中,我能够轻松地创建DbContext并从数据库中获取数据.但是,我也开始在整个应用程序中使用它.
我担心通过使用这种模式我错过了重大的设计/架构问题,我正在寻找IoC专家对此模式的评论.
.NET Core中是否有一种方法可以注册通用接口,并使其解析与某个实现相匹配的类.
例如,我有以下界面:
public interface IMapper<TFrom, TTo>
{
}
Run Code Online (Sandbox Code Playgroud)
我还有一个抽象类:
public abstract class Mapper<TFrom, TTo> : IMapper<TFrom, TTo>
{
protected Mapper()
{
// some generic stuff
}
public abstract TTo Map(TFrom);
}
Run Code Online (Sandbox Code Playgroud)
然后我可以创建一个这样的实现:
public class UserMapper : Mapper<Domain.User, Entity.User>
{
public override Entity.User Map(Domain.User from)
{
// do mapping
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法,使用默认的.NET Core DI进行注册IMapper<,>,让它自动解析类?
所以,例如,如果我在代码中的某个地方执行此操作:
class SomeClass
{
public SomeClass(IMapper<Domain.User, Entity.User> mapper) {}
}
Run Code Online (Sandbox Code Playgroud)
它以某种方式知道它应该解决这个类UserMapper<Domain.User, Entity.User>?
原因是手动注册每个映射器有点冗长,特定于实现.所以我希望Microsoft.DependencyInjection能够以某种方式自动解决其实现.
如何创建像下面的示例一样的复合实现,但使用本机 .NET Core DI 容器?
\n\n [TestFixture]\n public class CompositeTests\n {\n [Test]\n public void BuildComposite()\n {\n var container = new UnityContainer();\n container.RegisterType<IFoo, SomeFoo>("first");\n container.RegisterType<IFoo, AnotherFoo>("second");\n container.RegisterType<IFoo, CompositeFoo>();\n\n var instanceOfFoo = container.Resolve<IFoo>();\n\n Assert.IsInstanceOf<CompositeFoo>(instanceOfFoo);\n }\n }\n\n public class CompositeFoo : IFoo\n {\n public CompositeFoo(IFoo[] others)\n {\n Debug.Assert(others != null);\n Debug.Assert(others.Any());\n }\n }\n\n public class AnotherFoo : IFoo {}\n public class SomeFoo : IFoo {}\n public interface IFoo {}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n在这种情况下,复合\xe2\x80\x9c消耗\xe2\x80\x9d子对象的数组,并且在某种意义上\xe2\x80\x9csucks在\xe2\x80\x9d中使用密钥注册的IFoo的每个实现。\这是一个重要的方面:如果您要使用键注册组合,它将尝试实例化自身,从而立即导致 StackOverflowException。
\n
本机 DI 不支持这些命名注册。
\n\n这个例子是从这里提取的
\n我的 Windows 窗体应用程序中有一个文本框和一个按钮。当使用文本框中写入的值按下开始键时,应使用该值打开一个新表单。我想为每个打开的表单创建一个范围。当我关闭表单时,我想关闭相关范围。
如何使用简单的注入器创建自定义范围?
这是一个简单的示例代码
static class Program
{
static readonly Container container;
static Program()
{
container = new Container();
container.Register<MyProgram>();
//??
container.Register<MyCustomClass>(Lifestyle.Scoped);
container.Verify();
}
static void Main()
{
//Something...
}
}
class User
{
public int UserID { get; set; }
public string UserName { get; set; }
}
class MyCustomClass
{
User _user;
public MyCustomClass(User user)
{
_user = user;
}
public void Print()
{
Console.WriteLine(_user.UserName);
}
}
class MyProgram
{
public void StartNewScope(string username, int userid)
{ …Run Code Online (Sandbox Code Playgroud) 我一直在通过程序类向我的IOC容器注册我的依赖项,但它变得很乱.我决定编写一个DI提供程序,它提供并注册了它内部的依赖项.
在我开始用代码解释之前,这是VS给出的完整编译错误.
'ServiceCollection'不包含'AddSingleton'的定义无法解析符号'AddSingleton'
我尽量保持干净,在里面加入ServiceCollection类 DependencyProvider
public class DependencyProvider : ServiceCollection, IDependencyProvider
{
public DependencyProvider() : base()
{
Register();
}
public void Register()
{
base.AddSingleton<IContext, Context>(); // this line errors
new ServiceCollection().AddSingleton<IContext, Context>(); // this line works
}
}
Run Code Online (Sandbox Code Playgroud)
这是IDependencyProvider接口
public interface IDependencyProvider : IServiceCollection
{
void Register();
}
Run Code Online (Sandbox Code Playgroud)
我可以不这样做,还是我只是做错了什么?我真的希望它可能,因为解决方案看起来非常干净,请创建一个新的ServiceCollection实例并使用该字段.
只是为了澄清错误,我无法访问任何基本方法ServiceCollection,就像这样
base.AddSingleton<IContext, Context>();
Run Code Online (Sandbox Code Playgroud)
但是,这条线在内联新实例时起作用
new ServiceCollection().AddSingleton<IContext, Context>();
Run Code Online (Sandbox Code Playgroud) 我有一个使用Jersey 2.x的简单REST API项目.我尝试使用Google Guice来注入我的依赖项,但它似乎不起作用.我收到此错误:
org.glassfish.hk2.api.UnsatisfiedDependencyException:SystemInjecteeImpl没有可用于注入的对象(requiredType = AccountService,parent = AccountsResource,qualifiers = {},position = 0,optional = false,self = false,unqualified = null,1658198405 )
我有这个简单的资源类
@Path("/accounts")
@Produces(MediaType.APPLICATION_JSON)
public class AccountsResource {
private final AccountService accountService;
@Inject
public AccountsResource(AccountService accountService) {
this.accountService = accountService;
}
@GET
@Path("test")
public String test() {
return this.accountService.test();
}
Run Code Online (Sandbox Code Playgroud)
我想将此服务注入我的资源类
public class AccountService {
public AccountService() {}
public String test() {
return "test";
}
}
Run Code Online (Sandbox Code Playgroud)
因此,按照Guice的指南,我创建了这个模块类
import com.google.inject.*;
public class AccountsResourceModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountService.class); …Run Code Online (Sandbox Code Playgroud) 这篇文章https://medium.com/@dmitryzaets/legacy-net-applications-configuration-management-net-framework-4-5-1-68220335d9d8描述了如何将选项模式与 Autofac 一起使用。我试图将其翻译为与 Simple Injector 一起使用。但我没有运气。这是我的国际奥委会代码
public class IocBootstrap2
{
private Container Container { get; }
public IocBootstrap2()
{
Container = new Container();
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Configuration"))
.AddJsonFile("settings.json", optional: false, reloadOnChange: true);
var configuration = configurationBuilder.Build();
//Register Options
Container.Register(typeof(IOptions<>), typeof(OptionsManager<>));
Container.Register(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));
Container.Register(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));
Container.Register(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>));
// Register ConfigurationOptions
Container.RegisterConfigurationOptions2<MailingOptions>(configuration.GetSection("mailing"));
#if DEBUG
Container.Verify();
#endif
}
}
public static class ConfigurationSetupExtensions2
{
public static void RegisterConfigurationOptions2<TOptions>(this Container container, IConfiguration config)
where TOptions : class
{
container.Register(typeof(IOptionsChangeTokenSource<TOptions>), …Run Code Online (Sandbox Code Playgroud) configuration configurationmanager legacy-code simple-injector .net-core-configuration