应在web api控制器中创建实例 [英] Where instance should be created in web api controller

查看:68
本文介绍了应在web api控制器中创建实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在web api控制器中,我曾经使用关键字在中创建实例,所以一旦它从使用, GC 将被调用,内存将被释放。



我正在使用的代码,

  public   class  TemplateController:AutoVHCBaseApiController 
{

[路线( {id}) ]
[HttpGet]
[ResponseType( typeof (VHC.Core.Common.Beans.CheckTemplate))]
public IHttpActionResult Get( int id)
{
尝试
{
使用(ITemplateManager manager = new TemplateManager ())
{
CheckTemplate checkTemplate = manager.GetCheckTemplate(id,SiteCode);
return 确定(checkTemplate);
}
}
catch (ValidationException ex)
{
return BadRequest(ex.Message,FailureReason.ReasonCodeOptions.ValidationError);
}
}
}





我的一位同事让我修改如下:< br $> b $ b

  public   class  TemplateController:AutoVHCBaseApiController 
{
private readonly ITemplateManager manager;
public TemplateController()
{
manager = new TemplateManager( );
}

[路线( {id}) ]
[HttpGet]
[ResponseType( typeof (VHC.Core.Common.Beans.CheckTemplate))]
public IHttpActionResult Get( int id)
{
尝试
{
CheckTemplate checkTemplate = manager.GetCheckTemplate(id,SiteCode);
return 确定(checkTemplate);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message,FailureReason.ReasonCodeOptions.ValidationError);
}
}
}





我尝试了什么:



为什么我必须在constuctor中创建一个实例?

这两个代码与创建实例的区别是什么?

解决方案

首先使用的是没有做你认为的那样这样做,它只是在块的末尾为你调用dispose方法,它不会释放内存,只有在GC运行时才会发生,但这可能意味着内存会更快地被回收。当您需要使用时,取决于对象使用的资源。如果对象使用不受.net控制的资源(即数据库连接,网络连接,驱动器上的文件等),尽早调用Dispose将尽快释放这些资源(假设对象已正确写入)。网无法控制自己的一生。如果您没有显式处置该对象,那么外部资源将保留,直到GC转向调用Dispose。因此,如果TemplateManager在处理之前不打开非.net资源,则不需要使用使用。



至于构造函数vs方法有两个方面到此。如果在构造函数中创建对象,那么所有方法都可以使用manager知道变量确实指向TemplateManager的实例,如果三个不同的方法使用该对象,则只创建一个而不是每个方法创建自己的。在性能方面,这是非常重要的,因为性能最大的一个方面是分配和释放内存,这就是创建对象所做的事情。在构造函数中创建对象的第二个方面是,如果您使用依赖项注入(因为它是您想要使用的模式或者因为您想要开始单元测试),那么依赖项将通过构造函数注入,因此将会有最小的更改你的代码,它看起来像



 public TemplateController():this(new TemplateManager())
{
}

public TemplateController(ITemplateManager templateManager)
{
manager = new templateManager;
}





由于代码已经在构造函数中创建的对象周围编写,因此这将是一个非常简单的更改make。



显然这一切都假设TemplateManager *是*可重复使用的,如果不是这样的话,可以创建一次并使用很多次然后在构造函数中创建它是错误的,并且代码应该保持原样,


你写的内容绰绰有余,在我说什么之前,还有也没有必要让它 readonly ,因为你只是使用它来访问数据,而不是修改它的值(即使在第二个代码中)。



现在就像你说的那样,使用block是有效的,因为它会在对象超出范围时立即清除资源。所以我自己的偏好是使用block,而不是创建一个实例,然后在函数中访问它。在某些情况下,您可能需要使用该方法,例如,

  public   class  TemplateController:AutoVHCBaseApiController 
{
private readonly ITemplateManager经理;
public TemplateController()
{
manager = new TemplateManager( );
}

[路线( {id}) ]
[HttpGet]
[ResponseType( typeof (VHC.Core.Common.Beans.CheckTemplate))]
public IHttpActionResult Get( int id)
{
尝试
{
CheckTemplate checkTemplate = Process(args);
return 确定(checkTemplate);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message,FailureReason.ReasonCodeOptions.ValidationError);
}

// 清理资源
manager.Dispose();
}

// 注意我有一个新功能
private CheckTemplate Process( params list){
// 在这里使用经理。
}
}





1.您需要在多个函数上访问相同的实例 - 前提是您不想依赖参数传递。

2.多次创建实例有过载或延迟 - 磁盘加载等 - 在这种情况下,您可以定义单个实例,然后访问其状态和功能。

3.对象的实例化在所有方法处理程序中都是多余的,您可以通过这样做来最小化代码或实现DRY规则。

4. Singleton模式 - 但是还有其他一些实现,甚至要求你不必限制自己。

5.你的老板希望你这样做。



即使是这种情况,你也可以做到以下几点,

  public   class  TemplateController:AutoVHCBaseApiController 
{
private ITemplateManager manager;
public TemplateController()
{
// 不再需要。
manager = new TemplateManager();
}

[路线( {id}) ]
[HttpGet]
[ResponseType( typeof (VHC.Core.Common.Beans.CheckTemplate))]
public IHttpActionResult Get( int id)
{
尝试
{
// 使用属性进行申请。
使用(manager = new TemplateManager()){
CheckTemplate checkTemplate = Process(args);
return 确定(checkTemplate);
}
}
catch (ValidationException ex)
{
return BadRequest(ex.Message,FailureReason.ReasonCodeOptions.ValidationError);
}
}

// 注意我有一个新功能
private CheckTemplate Process( params list){
// 在这里使用经理。
}
}



换句话说,您只需要一个属性,如果您需要将其作为一个状态进行管理,或者您需要从多个函数访问它并拥有需要实例的私有函数和工作者,否则您可以有一个嵌套的使用块,可以很容易地做到这一点,并在退出之前,清理资源。



对我来说,进行更改并不是一个坏主意,而是将其设为 readonly 并在构造函数中实例化是一个糟糕的方法 - 它将被实例化为 POST PUT 请求,即使它不是必需的。


In web api controller, I used to create instance within using keyword, so Once it come out from the using, GC will be called and memory will be released.

The code which I'm using right now,

public class TemplateController : AutoVHCBaseApiController
    {

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                using(ITemplateManager manager=new   TemplateManager())
                {
                    CheckTemplate checkTemplate = manager.GetCheckTemplate(id, SiteCode);
                    return Ok(checkTemplate);
                }
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }
    }



One of my collegue asked me to modify like below:

public class TemplateController : AutoVHCBaseApiController
    {
        private readonly ITemplateManager manager;
        public TemplateController()
        {
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                CheckTemplate checkTemplate = manager.GetCheckTemplate(id, SiteCode);
                return Ok(checkTemplate);
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }
    }



What I have tried:

Why should i have to create a instance at constuctor?
What is the difference of the both code to creating instance?

解决方案

First of all using isn't doing what you think it is doing, it simply calls the dispose method for you at the end of the block, it doesn't release memory, that only happens when the GC runs however it may well mean the memory is reclaimed sooner. When you need to use using depends on what resources the object uses. If the object uses resources not controlled by .net (ie database connections, network connections, files on the drive and so on) calling Dispose as early as possible will release these resources as soon as possible (assuming the object is properly written) as .net can't control their lifetime. If you didn't dispose the object explicitly then the external resource would remain until GC gets around to calling Dispose. So if TemplateManager does not hold non .net resources open until it is disposed then there is no need to use "using".

As for constructor vs method there are two aspects to this. If you create the object in the constructor then all methods can use "manager" knowing that the variable does indeed point to an instance of TemplateManager, and if three different methods use the object then only one is created rather than each method creating its own. In terms of performance this is significant as one of the biggest drains on performance is allocating and deallocating memory which is what creating objects does. The second aspect to creating the object in the constructor is that if you use dependency injection (either because it is a pattern you want to use or because you want to start unit testing) then the dependencies are injected via the constructor so there will be minimal changes to your code, it would look something like

public TemplateController() : this (new TemplateManager())
{
}

public TemplateController(ITemplateManager templateManager)
{
    manager = new templateManager;
}



As the code is already written around the object being created in the constructor this will be a very easy change to make.

Obviously this all assumes that TemplateManager *is* re-usable, is that it is fine to create once and use many times, if that is not the case then creating it in the constructor is the wrong thing to do and the code should be left as it was,


What you were writing was more than enough, before I say anything else, there is also no need to make it readonly, as you are just using it to access data, not modify its values (even in the second code).

Now like you said, using block is efficient as it clears out resources as soon as the object gets out of scope. So my own preference would be using that using block, instead of creating an instance and then accessing it in the function. There are some cases where you might need to use that approach, such as,

public class TemplateController : AutoVHCBaseApiController
    {
        private readonly ITemplateManager manager;
        public TemplateController()
        {
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                CheckTemplate checkTemplate = Process(args);
                return Ok(checkTemplate);
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }

            // Clean up resources
            manager.Dispose();
        }

        // Notice I have a new function
        private CheckTemplate Process(params list) {
            // Use manager here.
        }
    }



1. You need to access the same instance on multiple functions — provided you do not want to rely on parameter passing.
2. Creating instance multiple times has an overload or latency — disk loading etc. — in such cases, you can have a single instance defined and then access its states and functions.
3. Instantiation of object is redundant in all method handlers, and you can minimize the code or implement DRY rule by doing so.
4. Singleton pattern — but that has some other implementations, even which require you to not have to restrict yourself.
5. Your boss wants you to do so.

Even if this is the case, then you can surely do the following,

public class TemplateController : AutoVHCBaseApiController
    {
        private ITemplateManager manager;
        public TemplateController()
        {
            // Not required anymore.
            manager = new TemplateManager();
        }

        [Route("{id}")]
        [HttpGet]
        [ResponseType(typeof(VHC.Core.Common.Beans.CheckTemplate))]
        public IHttpActionResult Get(int id)
        {
            try
            {
                // Apply using over a property. 
                using (manager = new TemplateManager()) {
                    CheckTemplate checkTemplate = Process(args);
                    return Ok(checkTemplate);
                }
            }
            catch (ValidationException ex)
            {
                return BadRequest(ex.Message, FailureReason.ReasonCodeOptions.ValidationError);
            }
        }

        // Notice I have a new function
        private CheckTemplate Process(params list) {
            // Use manager here.
        }
    }


In other words, you only need a property, if you need to manage it as a state, or you need to access it from multiple functions and have private functions and workers that require an instance, otherwise you can have a nested using block that can easily do the trick and before exiting, cleans up the resources.

For me, making the change was not a bad idea, but making it readonly and instantiating it in constructor was a bad approach — it will be instantiated for POST, PUT requests too, even if it is not required.


这篇关于应在web api控制器中创建实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆