2009-11-12 4 views
9

J'ai besoin d'accéder au HttpContext.Current à partir d'un service WCF RESTful. Je sais que je suis en mesure d'atteindre cet objectif en ajoutant ce qui suit à config:Comment définir ServiceHostingEnvironment.AspNetCompatibilityEnabled = true dans le code (pas dans la configuration) .NET/C#

<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” /> 

et en utilisant l'attribut suivant sur mon service:

[AspNetCompatibilityRequirements(RequirementsMode 
    = AspNetCompatibilityRequirementsMode.Required)] 

Voici ma question, je dois « spin up » une instance du service dans le code pour les tests unitaires et donc je ne peux pas utiliser les fichiers de configuration pour spécifier les bebaviours de service etc. Pour le moment, mon code ressemble à ceci, mais en dépit d'avoir parcouru le web, je n'ai pas pu déterminer comment Classe ServiceHostingEnvironment et définissez la propriété AspNetCompatibilityEnabled sur true sans utiliser de configuration, quelqu'un peut-il vous aider?

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

Toute aide est très appréciée et merci d'avance.

Répondre

-2

Envisager d'affacturage sur l'utilisation explicite de HttpContext.Current derrière un HttpContext.Current n'est défini que lorsque votre service wcf est hébergé dans une application web asp.net de toute façon - si un jour vous avez besoin de l'héberger comme un service wcf ordinaire, HttpContext .Current ne va pas être disponible

+5

Cela ne touche même pas à la façon de définir le AspNetCompatibilityEnabled qui est ce que 95% de sa question portait. –

0

Il est un cadre AppDomain à l'échelle que vous pouvez définir la classe la ServiceHostingEnvironment statique System.ServiceModel:

ServiceHostingEnvironment.AspNetCompatibilityEnabled = true; 

Cela devrait être fait avant de créer et d'ouvrir vos hôtes de service.

aurait été agréable - mais il est un paramètre en lecture seule, et la seule façon de le mettre semble être dans la configuration :-(

+0

Malheureusement, cette propriété n'a pas de setter. –

+0

Y at-il une solution de contournement pour cela? C'est incroyable que vous puissiez presque configurer complètement WCF par programme, sauf pour ce cas particulier. Je dirais que c'est un bug dans la WCF. Existe-t-il un moyen d'au moins dire à votre service de le faire pour vous? –

+0

@marc_s: Tout ce que vous avez à faire est de configurer l'atelier de maintenance (voir ma réponse), même s'il ne s'agit pas d'un service sur l'ensemble du site. –

4

Vous pouvez totalement faire cela, je ne sais pas ce que ces autres réponses sont, mais ils sont loin!

Il suffit de faire quelque chose comme:

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

- Modifier Cela supprime le comportement existant si elle existe, et ajoute un nouveau comportement qui a le mode que vous préférez. Mon exemple le définit sur .Allowed, mais vous pouvez bien sûr le régler sur le mode que vous désirez.

+0

Ceci définit juste si le service lui-même nécessite la compatibilité aspnet et non l'hôte. –

+0

Comment cela va-t-il définir la propriété 'AspNetCompatibilityEnabled' sur true? – drowa

0

expliquiez la réponse de Austin Harris:

Vous devez modifier le comportement de ServiceHost.
Parce que l'attribut est en lecture seule, vous devez supprimer et readd le comportement à ServiceHost.
Si vous disposez d'une application console ou d'un service Windows, cet hôte de service est défini.

Quelque chose comme ceci:

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

dans lequel le code de cas Austin Harris suffirait (s'il avait pas écrit admis au lieu de demande ...).Cependant, si vous avez intégré le service WCF dans une application ASP.NET, la tâche la plus difficile consiste à obtenir ServiceHost.

La clé est l'attribut factory du fichier de balisage YOUR_SERVICE.svc.

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

Ensuite, vous devez écrire votre propre usine.
Le code ci-dessous est VB.NET, je vais laisser au lecteur de le traduire en C# (vous aurez besoin de mettre WITH_FORMS_AUTHENTICATION à true par le chemin, et 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

Après avoir creusé avec Reflector, j'ai pu définir le drapeau AspNetCompatibilityEnabled en utilisant la réflexion. Cette approche a des inconvénients évidents, mais elle a fait le travail pour moi:

 // 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))); 
Questions connexes