如何在代码中设置ServiceHostingEnvironment.AspNetCompatibilityEnabled = true(不在配置中).NET / C#

我需要从RESTful WCF服务中使用-h访问HttpContext.Current。 我知道我可以通过在config中添加以下内容来实现此目的:

 

并在我的服务上使用以下属性:

 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 

这是我的问题,我需要在代码中“旋转”一个服务实例进行unit testing,因此我不能使用配置文件来指定服务bebaviours等。目前我的代码看起来如下,但尽管在网上搜索我我一直无法弄清楚如何设置ServiceHostingEnvironment类并将AspNetCompatibilityEnabled属性设置为true而不使用config,任何人都可以帮忙吗?

 string serviceUrl = "http://localhost:8082/MyService.svc"; _host = new ServiceHost(typeof(MyService), new Uri[] { new Uri(serviceUrl) }); ServiceEndpoint serviceEndpoint = _host.AddServiceEndpoint(typeof(IMyService), new WebHttpBinding(), string.Empty); serviceEndpoint.Behaviors.Add(new WebHttpBehavior()); // Here's where I'm stuck, i need something like... ServiceHostingEnvironmentSection shes = new ServiceHostingEnvironmentSection(); shes.AspNetCompatibilityEnabled = true; _host.Add(shes); _host.Open(); 

任何帮助都非常感谢,并提前感谢。

考虑将HttpContext.Current的显式使用分解为在unit testing期间可以存根的接口。

HttpContext.Current仅在您的wcf服务托管在asp.net Web应用程序中时定义 – 如果有一天您需要将其作为普通的wcf服务托管,HttpContext.Current将无法使用。

你可以完全做到这一点,我不知道这些其他答案是什么,但他们离开了!

做一些像:

 _host = new ServiceHost(...); // Remove existing behavior as it is readOnly for (int i = 0; i < _host.Description.Behaviors.Count; i++) { if (_host.Description.Behaviors[i] is AspNetCompatibilityRequirementsAttribute) { _host.Description.Behaviors.RemoveAt(i); break; } } // Replace behavior with one that is configured the way you desire. _host.Description.Behaviors.Add(new AspNetCompatibilityRequirementsAttribute { RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed }); _host.Open(); 

- 编辑这将删除现有行为(如果存在),然后添加具有您喜欢的模式的新行为。 我的示例将其设置为.Allowed,但您当然可以将其设置为您想要的模式。

这是一个AppDomain范围的设置,您可以在System.ServiceModel中的静态ServiceHostingEnvironment类上设置:

  ServiceHostingEnvironment.AspNetCompatibilityEnabled = true; 

这应该在您创建和打开服务主机之前完成。

本来不错 – 但它是一个只读设置,设置它的唯一方法似乎是通过配置:-(

详细说明Austin Harris的答案:

您需要更改ServiceHost的行为。
由于该属性是只读的,因此您需要删除并将行为读取到ServiceHost。
如果您有控制台应用程序或Windows服务,则将定义此servicehost。

像这样的东西:

 public static void Main() { using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService))) { try { // Open the ServiceHost to start listening for messages. serviceHost.Open(); // The service can now be accessed. Console.WriteLine("The service is ready."); Console.WriteLine("Press  to terminate service."); Console.ReadLine(); // Close the ServiceHost. serviceHost.Close(); } catch (TimeoutException timeProblem) { Console.WriteLine(timeProblem.Message); Console.ReadLine(); } catch (CommunicationException commProblem) { Console.WriteLine(commProblem.Message); Console.ReadLine(); } } } 

在这种情况下,Austin Harris的代码就足够了(如果他没有写过Allowed而不是Required ……)。

但是,如果将WCF服务集成到ASP.NET应用程序中,那么棘手的部分就是获取ServiceHost。

键是YOUR_SERVICE.svc标记文件中的factory属性。

 <%@ ServiceHost Factory="ApertureImportBelegung.DerivedFactory" Language="VB" Debug="true" Service="ApertureImportBelegung.ImportBelegung" CodeBehind="Service1.svc.vb" %> 

然后你需要自己编写工厂。
下面的代码是VB.NET,我将把它留给读者将其翻译成C#(顺便说一下,你需要将WITH_FORMS_AUTHENTICATION设置为true,而C#ps: http ://converter.telerik.com)

 'Imports System.ServiceModel Imports System.ServiceModel.Description 'Imports System.ServiceModel.Dispatcher 'Imports System.ServiceModel.Channels 'Imports System.ServiceModel.Configuration Imports System.ServiceModel.Activation ' Add reference to assembly System.ServiceModel.Activation.dll Public Class DerivedHost Inherits ServiceHost Public Sub New(t As Type, ParamArray baseAddresses() As Uri) MyBase.New(t, baseAddresses) End Sub Protected Overrides Sub OnOpening() 'Me.Description.Behaviors.Add(New mys) 'Me.Description.Add(New MyServiceBehavior()) 'Me.Description.Behaviors.Add(New WcfMessageLoggerExtension()) MyBase.OnOpening() End Sub End Class ' DerivedHost ' http://msdn.microsoft.com/en-us/library/aa702697(v=vs.110).aspx Public Class DerivedFactory Inherits ServiceHostFactory Protected Overrides Function CreateServiceHost(t As Type, baseAddresses As Uri()) As ServiceHost Return New DerivedHost(t, baseAddresses) End Function ' CreateServiceHost 'Then in the CreateServiceHost method, we can do all of the 'things that we can do in a self-hosted case: Public Overrides Function CreateServiceHost(service As String, baseAddresses As Uri()) As ServiceHostBase Application.ConfigData.ReadConfigData() ' The service parameter is ignored here because we know our service. Dim serviceHost As New ServiceHost(GetType(ImportBelegung), baseAddresses) ' System.ServiceModel.ServiceHostingEnvironment.AspNetCompatibilityEnabled = True ' http://stackoverflow.com/questions/13597408/wcf-message-inspector-is-not-working 'Dim serviceHost As New System.ServiceModel.ServiceHost(GetType(ImportBelegung)) 'serviceHost.Description.Behaviors.Add(New WcfMessageLoggerExtension()) ' http://stackoverflow.com/questions/5907791/how-to-programatically-create-a-wcf-service-and-its-metadata-on-the-same-url ' http://msdn.microsoft.com/en-us/library/system.servicemodel.servicehost(v=vs.110).aspx ' host.Open() 'This example iterates through all the ServiceEndpoint objects and adds ConsoleMessageTracing as an endpoint behavior: For Each endpoint As ServiceEndpoint In serviceHost.Description.Endpoints 'endpoint.Behaviors.Add(New WcfMessageLoggerExtension()) 'endpoint.Behaviors.Add(New ConsoleOutputBehaviorExtensionElement) endpoint.Behaviors.Add(New MessageInspector.ConsoleOutputBehavior) endpoint.Behaviors.Add(New HeaderInspector.ConsoleOutputHeaderBehavior) Next endpoint ' Ensure (in ) aspNetCompatibilityEnabled="true" -->  #Const WITH_FORMS_AUTHENTICATION = False #If WITH_FORMS_AUTHENTICATION Then For i As Integer = 0 To serviceHost.Description.Behaviors.Count - 1 Step 1 If TypeOf serviceHost.Description.Behaviors(i) Is AspNetCompatibilityRequirementsAttribute Then serviceHost.Description.Behaviors.RemoveAt(i) Exit For End If Next i serviceHost.Description.Behaviors.Add(New AspNetCompatibilityRequirementsAttribute() With {.RequirementsMode = AspNetCompatibilityRequirementsMode.Required}) #End If Return serviceHost End Function ' CreateServiceHost End Class ' DerivedFactory 

在使用Reflector挖掘之后,我能够使用reflection设置AspNetCompatibilityEnabled标志。 这种方法有明显的缺点,但它为我完成了这项工作:

  // get the ServiceHostingEnvironmentSection by calling an internal static method var section = (ServiceHostingEnvironmentSection)typeof(ServiceHostingEnvironmentSection).GetMethod("UnsafeGetSection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).Invoke(null, null); // set the read-only flag to false so values can be updated typeof(ServiceHostingEnvironmentSection).BaseType.BaseType.GetField("_bReadOnly", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(section, false); // set the AspNetCompatibilityEnabled value section.AspNetCompatibilityEnabled = true; // now one can add a Service Route routes.Add(new ServiceRoute("MyRoutePrefix", new ServiceHostFactory(), typeof(MyService)));