2013-04-15 24 views
6

Ho un servizio Restent WCF che sto ospitando come servizio di Windows. Voglio aggiungere il supporto per più domini al mio servizio. Tuttavia, posso farlo facilmente quando uso il file global.asax. Ma voglio ospitare il mio servizio come servizio di Windows.Condivisione di risorse Cross Origin per C# WCF Servizio Web restful ospitato come servizio di Windows

Ho creato un progetto che ospita il mio servizio come servizio di Windows. Ora il problema che sto affrontando è, non sono in grado di aggiungere il supporto per il dominio incrociato ora. Ho provato tutte le possibili soluzioni che ho trovato attraverso il file app.config, ma nessuno funziona. Ho provato le soluzioni su questi link:

dotnet tricks

enable-cors.org

ho provato a fissare l'intestazione nel codice utilizzando la seguente funzione chiamando in ogni metodo di contratto di servizio.

private static void SetResponseHeader() 
{ 
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*"); 
WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache, no-store"); 
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Request-Methods", "GET, POST, PUT, DELETE, OPTIONS"); 
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept"); 
} 

Interfaccia:

namespace ReaderService 
{ 
[ServiceContract] 
public interface INFCReader 
{ 
    [OperationContract] 
    [WebInvoke(UriTemplate = "GetLogin", Method = "POST")] 
    GetLoginResults GetLogin(DisplayRequest dispRequest); 
} 

Ecco DisplayRequest è una classe.

Si prega di aiutare ragazzi. Fammi sapere se qualcuno vuole dare un'occhiata a qualsiasi altro codice.

Grazie mille.

EDIT :::::::

Grazie mille per la risposta Thomas. Ho creato una classe MessageInspector che implementa IDispactchMessageInspector. Ho il codice seguente nella classe MessageInspector.

public class MessageInspector : IDispatchMessageInspector 
{ 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
     HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); 
     if (HttpContext.Current.Request.HttpMethod == "OPTIONS") 
     { 
      HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache"); 
      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST"); 
      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept"); 
      HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000"); 
      HttpContext.Current.Response.End(); 
     } 
     return null; 
    } 
} 

L'errore che sto ottenendo ora è: "Riferimento oggetto non impostato su un'istanza di un oggetto". L'errore è in questa linea di codice sopra

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); 

Tutto quello che voglio fare è aggiungere il supporto CORS al mio servizio web. Per favore fatemi sapere se lo sto facendo correttamente. O c'è un altro modo per fare lo stesso.

risposta

10

Finalmente ho trovato una soluzione alle mie domande.

È tutto qui. Supporting Cross Origin Resource

Bella spiegazione passo passo. Immagino di non averlo mai capito da solo.

CODICE:

creare 2 classi come segue:

  1. MessageInspector attuazione IDispatchMessageInspector.
  2. BehaviorAttribute in esecuzione Attribute, IEndpointBehavior e IOperationBehavior.

Con i seguenti dati:

//MessageInspector Class 
using System; 
using System.ServiceModel; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Dispatcher; 
using System.ServiceModel.Description; 
namespace myCorsService 
{ 
    public class MessageInspector : IDispatchMessageInspector 
    { 
    private ServiceEndpoint _serviceEndpoint; 

    public MessageInspector(ServiceEndpoint serviceEndpoint) 
    { 
     _serviceEndpoint = serviceEndpoint; 
    } 

    /// <summary> 
    /// Called when an inbound message been received 
    /// </summary> 
    /// <param name="request">The request message.</param> 
    /// <param name="channel">The incoming channel.</param> 
    /// <param name="instanceContext">The current service instance.</param> 
    /// <returns> 
    /// The object used to correlate stateMsg. 
    /// This object is passed back in the method. 
    /// </returns> 
    public object AfterReceiveRequest(ref Message request, 
              IClientChannel channel, 
              InstanceContext instanceContext) 
    { 
     StateMessage stateMsg = null; 
     HttpRequestMessageProperty requestProperty = null; 
     if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name)) 
     { 
     requestProperty = request.Properties[HttpRequestMessageProperty.Name] 
          as HttpRequestMessageProperty; 
     } 

     if (requestProperty != null) 
     { 
     var origin = requestProperty.Headers["Origin"]; 
     if (!string.IsNullOrEmpty(origin)) 
     { 
      stateMsg = new StateMessage(); 
      // if a cors options request (preflight) is detected, 
      // we create our own reply message and don't invoke any 
      // operation at all. 
      if (requestProperty.Method == "OPTIONS") 
      { 
      stateMsg.Message = Message.CreateMessage(request.Version, null); 
      } 
      request.Properties.Add("CrossOriginResourceSharingState", stateMsg); 
     } 
     } 

     return stateMsg; 
    } 

    /// <summary> 
    /// Called after the operation has returned but before the reply message 
    /// is sent. 
    /// </summary> 
    /// <param name="reply">The reply message. This value is null if the 
    /// operation is one way.</param> 
    /// <param name="correlationState">The correlation object returned from 
    /// the method.</param> 
    public void BeforeSendReply(ref Message reply, object correlationState) 
    { 
     var stateMsg = correlationState as StateMessage; 

     if (stateMsg != null) 
     { 
     if (stateMsg.Message != null) 
     { 
      reply = stateMsg.Message; 
     } 

     HttpResponseMessageProperty responseProperty = null; 

     if (reply.Properties.ContainsKey(HttpResponseMessageProperty.Name)) 
     { 
      responseProperty = reply.Properties[HttpResponseMessageProperty.Name] 
          as HttpResponseMessageProperty; 
     } 

     if (responseProperty == null) 
     { 
      responseProperty = new HttpResponseMessageProperty(); 
      reply.Properties.Add(HttpResponseMessageProperty.Name, 
           responseProperty); 
     } 

     // Access-Control-Allow-Origin should be added for all cors responses 
     responseProperty.Headers.Set("Access-Control-Allow-Origin", "*"); 

     if (stateMsg.Message != null) 
     { 
      // the following headers should only be added for OPTIONS requests 
      responseProperty.Headers.Set("Access-Control-Allow-Methods", 
             "POST, OPTIONS, GET"); 
      responseProperty.Headers.Set("Access-Control-Allow-Headers", 
        "Content-Type, Accept, Authorization, x-requested-with"); 
     } 
     } 
    } 
    } 

    class StateMessage 
    { 
    public Message Message; 
    } 
} 

//BehaviorAttribute Class 
using System; 
using System.ServiceModel.Channels; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 

namespace OpenBetRetail.NFCReaderService 
{ 
    public class BehaviorAttribute : Attribute, IEndpointBehavior, 
           IOperationBehavior 
    {   
    public void Validate(ServiceEndpoint endpoint) { } 

    public void AddBindingParameters(ServiceEndpoint endpoint, 
          BindingParameterCollection bindingParameters) { } 

    /// <summary> 
    /// This service modify or extend the service across an endpoint. 
    /// </summary> 
    /// <param name="endpoint">The endpoint that exposes the contract.</param> 
    /// <param name="endpointDispatcher">The endpoint dispatcher to be 
    /// modified or extended.</param> 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
             EndpointDispatcher endpointDispatcher) 
    { 
     // add inspector which detects cross origin requests 
     endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
              new MessageInspector(endpoint)); 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, 
            ClientRuntime clientRuntime) { } 

    public void Validate(OperationDescription operationDescription) { } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, 
            DispatchOperation dispatchOperation) { } 

    public void ApplyClientBehavior(OperationDescription operationDescription, 
            ClientOperation clientOperation) { } 

    public void AddBindingParameters(OperationDescription operationDescription, 
          BindingParameterCollection bindingParameters) { } 

    } 
} 

Dopo questo tutto quello che dovete fare è aggiungere questo messaggio ispettore di riparare il comportamento punto finale.

ServiceHost host = new ServiceHost(typeof(myService), _baseAddress); 
foreach (ServiceEndpoint EP in host.Description.Endpoints) 
      EP.Behaviors.Add(new BehaviorAttribute()); 

Grazie ragazzi per il vostro aiuto.

+1

Si noti che le risposte di solo collegamento sono scoraggiate, i riferimenti tendono a diventare obsoleti nel tempo. Si prega di considerare l'aggiunta di una sinossi autonoma qui, mantenendo il collegamento come riferimento. – Ren

+0

Grazie Ren. Pubblicheremo la soluzione reale. :) – Newbee

+1

Questo mi ha davvero aiutato molto! Grazie mille. –

1

Credo che la cosa più vicina ad Application_BeginRequest nel mondo WCF sono Message Inspectors:

Un messaggio ispettore è un oggetto estensibilità che può essere utilizzato nel client runtime e la spedizione di esecuzione del modello di servizio a livello di codice o attraverso la configurazione e che può ispezionare e modificare i messaggi dopo che sono stati ricevuti o prima che vengano inviati.

Per poter utilizzare messaggio personalizzato ispettori dovrete:

  1. Creare una classe che implementa l'IDispatchMessageInspector interfaccia (vostro ispettore personalizzato)
  2. Aggiungi l'ispettore personalizzato per il vostro servizio di DispatchRuntime.MessageInspectors raccolta

Here è possibile trovare ulteriori informazioni e alcuni esempi di codice su come fare questo.

+0

Grazie mille Thomas. Ho implementato Message Inspector. Sto ottenendo un altro errore nel mio servizio. Si prega di consultare la modifica. Grazie. – Newbee

+0

Prego. Vedo che hai già trovato una soluzione per il tuo nuovo problema. Ciò accadeva perché ** HttpContext ** non è disponibile dai servizi WCF a meno che non si abiliti la modalità di compatibilità ASP.NET, ma suppongo che funzionerebbe solo quando il servizio WCF è ospitato su IIS. –

+0

Ohh capisco. Grazie Thomas per il tuo aiuto. Mi hai mostrato il percorso corretto. :) – Newbee

Problemi correlati