2009-11-12 77 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))); 
相關問題