在Asp.net Core中,依赖注入,如何在Singleton对象中执行范围obj

时间:2017-03-01 12:30:34

标签: .net dependency-injection singleton

我有以下类定义:

public class A {
    private readonly B _b;
    public A (B b){ _b = b; }
}

public class B {
    private readonly  C _c;
    public B (C c) { _c = c; }
}

public class C {
    public string IP;
}

以下注册:

services.AddSingleton<A>();
services.AddSingleton<B>();
services.AddScoped<C>(a => {
    var accessor = a.GetService<Microsoft.AspNetCore.Http.IHttpContextAccessor>();
    var header = accessor.HttpContext.Request.Headers;
    return new C { IP = header["X_FORWARDED_FOR"] };
});

C.IP是一样的,

我希望它为每个客户端用户更改,而A B是单例。

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:1)

有多种方法可以解决这个问题,但最优雅的方法如下。您只需将public class C { private IHttpContextAccessor _accessor; public C(IHttpContextAccessor accessor) { _accessor = accessor; } public string IP => accessor.HttpContext.Request.Headers["X_FORWARDED_FOR"]; } 更改为:

即可
IHttpContextAccessor

HttpContext是ASP.NET Core中的单例,调用其HttpContext属性将始终返回当前请求的C。这允许services.AddSingleton<A>(); services.AddSingleton<B>(); services.AddSingleton<C>(); 成为无国籍和单身。

这使您可以将注册简化为以下内容:

C

如果在不依赖于ASP.NET的程序集中定义IC(例如业务层),这可能会给您带来问题。

通过为C引入抽象B并让IC取决于public interface IC { } public class B { private readonly IC _c; public B (IC c) { _c = c; } } ,可以优雅地解决此问题:

IC

这样我们就可以将B放在应用程序的基础层中(因此C可以访问它)并将IHttpContextAccessor实现移到Composition Root可以依赖public class C : IC { private readonly IHttpContextAccessor _accessor; public C(IHttpContextAccessor accessor) { _accessor = accessor; } public string IP => accessor.HttpContext.Request.Headers["X_FORWARDED_FOR"]; } 的应用程序。

C

为此,您需要将services.AddSingleton<IC, C>(); 的注册更改为:

 Stream stream = client.GetStream();

    StreamWriter sw = new StreamWriter(client.GetStream(), Encoding.ASCII);
    StreamReader sr = new StreamReader(client.GetStream(), Encoding.ASCII);

 else if (args.Length == 2)
        {
            while (args[1] != response)
            {
                //  response = sr.ReadLine();
                if (args[1] != response)
                {

                    // this is what should be put in sw.write for the updated database entry
                    // <name><space><location><CR><LF>
                    // cssbct +  " " + "is in fenner", so "cssbct location has changed"
                    // args[0] + " " + response


                    // response is now what the arg is
                    response = args[1];
                    // write the new response so that it will be sent to the server
                    sw.WriteLine(args[0] + " " + response);
                    // send it to the server
                      sw.Flush();


                    // write out the args and that the location has changed
                    //  Console.WriteLine(args[0] + " " + " location changed to be" + " " + response);

                    // Just testing what the response should be 
                    Console.WriteLine(args[0] + " " + response);


                    string Response2 = "";
                    // read the response from the server
                    Response2 = sr.ReadLine();



                    // if it equals "OK" do this
                    if (Response2 == "OK")
                    {
                        // drops connection to the server
                        // probably not what is needed but look at later date
                        Console.WriteLine(response);

                        Console.WriteLine("Client connection closed");
                        client.Close();
                    }

                    if (sr.EndOfStream)
                    {
                        Console.WriteLine("End of stream has been reached");
                    }