2010-08-09 42 views
1

我正在构建将在公司内部使用的ASP.NET Web服务。异常和跟踪/审计日志记录将由Web服务类以及Web服务将调用的业务对象执行。日志记录由内部开发的日志助手类的实例处理。日志帮助程序必须是一个实例,因为它跟踪了状态和用于将日志消息关联到组中的引用guid。如何在asp.net web服务中存储对象以便业务对象可以引用该对象?

在过去,我们通过使用方法参数将对日志帮助器实例的引用传递给类来处理这种情况。我试图找到一种可靠的方法来找到一种方法来存储和访问整个调用实例,而不必明确地通过它。

我试图在Web服务调用的早期阶段将实例存储在HTTPContext中。当我的业务对象稍后在调用期间需要它时,它们将作为基类的一个属性来访问它,以便继承我所有的对象。

最初我尝试将实例存储在Web服务的Context.Cache中。这似乎工作,我的研究使我相信Cache将是线程安全的。直到我从超过3个并发会话开始调用Web服务时,记录器的实例才会从呼叫共享到呼叫,而不是为每个呼叫重新创建。我尝试了Context.Application,发现与Cache存储非常相似的结果。

我能够通过Context.Session找到可用的解决方案。这要求我在每个方法的属性中使用EnableSession = true,但它似乎确保每个调用都保持实例唯一。我不需要跟踪通话间的数据,所以我不会将会话cookie存储在客户端空间中。

会话是我需要的最佳存储点吗?这似乎有点沉重,因为我不需要跟踪通话之间的会话。我愿意接受建议或批评。我确定有人会建议使用内置的Trace记录或Elmah等系统。这些可能是未来的一个选择,但现在我没有时间走下去。

更新:我应该澄清,此服务将需要在.Net Framework 2.0上运行。我们正在转移到3.5/4.0,但我们目前的生产服务器是最高2.0的Win2000。

+0

顺便说一句,术语“对象实例”是多余的。一个对象是一个类的实例。 – 2010-08-09 19:33:10

+0

感谢您更新问题。 “一个对象的实例”是我成长起来的东西,但绝不会试图争辩正确。 – 2010-08-09 20:27:18

回答

1

我认为,过去,您在Windows窗体应用程序中使用了这些业务对象?

您不应该让您的业务对象依赖于某些环境对象。相反,您应该使用构造函数注入属性注入将记录器对象传递给业务对象。记录器应该由接口表示,而不是由具体的类表示。应该将业务对象传递给实现此接口的某个类的引用。他们应该从来没有知道这个对象的存储位置。这将使您能够测试Web服务之外的业务对象。

然后,您可以将记录对象存储在任何你喜欢的地方。我建议将它存储在HttpContext.Current.Items中,它只对当前请求有效。


public interface ILogger 
{ 
    void Log(string message); 
} 

public class Logger : ILogger 
{ 
    public void Log(string message) {} 
} 

public class BusinessObjectBase 
{ 
    public BusinessObjectbase(ILogger logger) 
    { 
     Logger = logger; 
    } 

    protected ILogger Logger {get;set;} 
} 

public class BusinessObject : BusinessObjectBase 
{ 
    public void DoSomething() 
    { 
     Logger.Log("Doing something"); 
    } 
} 
+0

日志记录库位于WinForm和WebForm应用程序中。我正在从事的许多遗留代码基础不是基于对象的,也不必担心我的代码所做的相同事情。 HttpContext.Current.Items正在工作,我需要并回答我的问题。我已经接受了基于此的答案。 你是指使用某种形式的依赖注入?我一直在看直接投资,并计划使用它,但不能争辩,直到我能够坚定地理解它。你会如此善良,以我的问题中描述的情景发表你描述的例子吗? – 2010-08-09 20:55:11

+0

谢谢约翰。你的例子非常接近我认为你的建议。我的问题是,我有一些使用具有多个参数的构造函数创建的对象,我也有需要记录的静态方法。我是否需要扩展那些具有其他参数或者有其他方法?我简短地看了一下Unity和Castle Windsor,但是现在看起来都太复杂了。 – 2010-08-09 21:10:12

+0

@Chris:首先,你找到了一个不使用静态方法的原因:-)。是的,您必须将这些作为构造函数参数传递给需要使用日志的任何内容,除非它们已经有一些共同的对象。在这种情况下,您可以将ILogger实例放入该通用对象中。 – 2010-08-09 22:48:14

2

你可以尝试使用OperationContext.Current。这将使您能够在Web服务调用的整个生命周期中存储变量。

编辑为可能的无WCF解决方案: 由于您没有WCF,因此可以通过为对象创建线程ID的静态映射来创建类似于线程本地存储的内容。只要确保在请求完成时正确清理此静态映射,或者使用该线程的下一个调用将拾取对象。另外,请确保在访问地图时锁定地图。

+0

这看起来像一个非常有前途的选项,但我被锁定到.Net Framework 2.0。希望我们很快就能完成从Windows 2000迁移的工作,并且我将选择3.5/4.0作为选项。 – 2010-08-09 18:41:46

0

我的理解是,一个ASMX类实例化每个呼叫。因此,您似乎可以在ASMX的构造函数中实例化您的日志助手类,并将其存储在实例变量中。 ASMX类中的所有处理都会引用该实例变量。这样,一个web服务调用的整个生命周期中将使用相同的日志帮助器实例,并且不会在多个调用中共享。

这很可能会在一个通用的超类中实现,所有的ASMX类将从这个超类继承。虽然我猜想没有什么能够阻止你在每个ASMX类中反复实现它,如果由于某种原因你会避开一个普通的超类。

+0

这不会是一个干净的构建业务类的方法,因为它们的超类对象必须从System.Web.Services.WebService继承。这对于在简单的业务对象中拖延很有帮助。尽管接口可能会提供一个可能的解决方案。 – 2010-08-09 20:59:27

+0

对不起,如果我误解你的问题 - 我绝对同意这将是一个可怕的想法,你的业务对象从WebService的子类!但是,对于您的业务对象直接引用Context或Session也是不利的,因为它会阻止它们在不同的上下文(Windows服务,控制台应用程序等)中被重用。我假定ASMX类将管理日志助手实例的生命周期,并根据需要将其提供给业务类。 – mikemanne 2010-08-10 17:59:38

相关问题