2009-11-12 78 views
9

我有一个要求,可以从RESTful WCF服务中访问HttpContext.Current。我知道我能做到这一点通过添加以下来配置:如何在代码中设置ServiceHostingEnvironment.AspNetCompatibilityEnabled = true(不在配置中).NET/C#

<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” /> 

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

[AspNetCompatibilityRequirements(RequirementsMode 
    = AspNetCompatibilityRequirementsMode.Required)] 

这里是我的问题,我需要“旋转起来”在代码中的服务实例单元测试,因此我不能使用配置文件来指定服务bebaviours等 目前我的代码看起来像下面,但尽管淘网,我一直无法解决如何设置一个ServiceHostingEnvironment类并将AspNetCompatibilityEnabled属性设置为true而不使用配置,任何人都可以帮忙吗?

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(); 

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

回答

-2

考虑分解出后面的明确使用HttpContext.Current的唯一途径接口,您可以在单元测试期间将其剔除

HttpContext.Current仅在您的wcf服务托管在asp.net Web应用程序中时才被定义 - 如果有一天您需要将其作为普通wcf服务托管,HttpContext当前不可用

+5

这甚至不涉及如何设置AspNetCompatibilityEnabled,这是他的问题的95%。 – 2013-12-10 23:57:44

0

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

ServiceHostingEnvironment.AspNetCompatibilityEnabled = true; 

您创建和打开您的服务主机之前,这应该做的。

本来不错 - 但它是一个只读设置,并设置它似乎是通过配置:-(

+0

不幸的是,财产没有setter。 – 2009-11-12 11:28:15

+0

有没有解决方法?令人惊讶的是,除了这种特殊情况之外,您几乎可以完全以编程方式配置WCF。我会称这是WCF中的一个错误。有没有办法至少告诉你的服务为你做? – 2011-08-03 18:38:41

+0

@marc_s:您需要做的就是设置服务工厂(请参阅我的答案),尽管这不是整个网站,只是整个服务范围。 – 2014-10-08 12:48:40

4

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

就做这样的事情:

_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,但你当然可以将它设置为你想要的模式。

+0

这只是设置如果服务本身需要aspnet兼容性而不是主机。 – 2015-06-29 10:00:11

+0

如何将'AspNetCompatibilityEnabled'属性设置为true? – drowa 2017-05-22 20:34:33

0

阐述奥斯汀·哈里斯的回答:

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

事情是这样的:

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 <ENTER> 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(); 
    } 
    } 
} 

在这种情况下,奥斯汀哈里斯的代码就足够了(如果他不写允许的,而不是必需的......)。

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

关键是YOUR_SERVICE.svc标记文件中的工厂属性。

<%@ 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 <system.serviceModel>) aspNetCompatibilityEnabled="true" --> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" 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 
0

在使用Reflector进行挖掘后,我可以使用反射来设置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))); 
相关问题