2008-10-19 9 views
27

Je travaille actuellement sur MVC, mais sur ma liste «Pour apprendre à un moment donné», j'ai aussi WCF.ASP.NET MVC et WCF

Je me demande simplement si WCF est quelque chose qui devrait/pourrait être utilisé dans une application MVC ou non? L'arrière-plan est que je veux une application de bureau (.NET 3.5, WPF) interagir avec mon site Web MVC, et je me demande quel est le meilleur moyen de transférer des données entre les deux. Dois-je utiliser des vues spéciales/les contrôleurs doivent-ils retourner JSON ou XML (en utilisant ContentResult)?

Et peut-être encore plus important, pour l'inverse, pourrais-je appeler des contrôleurs spéciaux? Je ne sais pas comment l'autorisation fonctionnerait dans un tel contexte. Je peux utiliser l'authentification Windows ou (si le site exécute l'authentification par formulaires) que l'utilisateur stocke ses informations d'identification dans l'application, mais je créerais alors essentiellement un client HTTP dans mon application. Donc, alors que MVC => Application semble vraiment facile, Application => MVC semble être un peu difficile et une utilisation possible pour WCF? Je ne cherche pas à forcer brute-force WCF dans ceci, mais je me demande juste s'il y a en fait un bon cas d'utilisation pour WCF dans une application MVC.

Répondre

47

Les services WCF peuvent être utiles dans cette situation, mais ne créez pas de services alignés avec votre interface utilisateur, créez des services alignés sur les processus métier. c'est à dire. vous n'aurez pas de service qui renvoie les données d'affichage pour chaque page, vous aurez un service qui expose les opérations logiques. Ensuite, votre site peut appeler les mêmes services que ceux que le client Windows appelle, mais vous n'avez pas besoin de coupler la conception du client Windows à la conception du site Web.

Au lieu de cela:

Client Windows -> Services -> Site Web

Il devrait être:

Client Windows -> Services

Site Web -> Services

+0

Il m'a fallu du temps pour vraiment comprendre cela, mais c'est logique. WCF en tant qu'hôte de service pour plusieurs clients, mvc en tant que site Web qui traduit les appels de service en s ui. –

9

Vous pouvez utiliser ADO.NET Data Services pour partager vos données avec JSON (pour les clients JavaScript) ou XML (pour les applications de bureau). ASP.NET MVC peut alors tirer parti de cela en utilisant l'un des deux dans le modèle. Comme vous le savez probablement, ADO.NET Data Services est basé sur WCF, donc vous étiez sur la bonne voie.

8

J'utilise asp.net mvc à la fois comme site Web html (moteur de vue par défaut) et comme point de terminaison de service. Le point de terminaison de service est utilisé par mes clients WPF et Silverlight en injectant «content-type = text/xml» dans l'en-tête d'une requête WebClient (voir post de ScottGu sur la consommation d'un service dans SL qui a inspiré cette approche). J'ai trouvé quelque part sur le net, un code qui remplace l'événement OnActionExecuted comme ceci:

public class JsonOrXml : ActionFilterAttribute 
{ 
    private static UTF8Encoding UTF8 = new UTF8Encoding(false); 

    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     // setup the request, view and data 
     HttpRequestBase request = filterContext.RequestContext.HttpContext.Request; 
     ViewResult view = (ViewResult)(filterContext.Result); 
     var data = view.ViewData.Model; 

     String contentType = request.ContentType ?? string.Empty; 

     // JSON 
     if (contentType.Contains("application/json") || (string)view.ViewData["FORMAT"] == "json") 
     { 
      filterContext.Result = new JsonResult 
      { 
       Data = data 
      }; 
     } 

     // POX 
     else if (contentType.Contains("text/xml") || (string)view.ViewData["FORMAT"] == "xml") 
     { 
      // MemoryStream to encapsulate as UTF-8 (default UTF-16) 
      // http://stackoverflow.com/questions/427725/ 
      // 
      // MemoryStream also used for atomicity but not here 
      // http://stackoverflow.com/questions/486843/ 
      //using (MemoryStream stream = new MemoryStream(500)) 
      //{ 
      // using (var xmlWriter = 
      //  XmlTextWriter.Create(stream, 
      //   new XmlWriterSettings() 
      //   { 
      //    OmitXmlDeclaration = false, 
      //    Encoding = UTF8, 
      //    Indent = true 
      //   })) 
      // { 
      //  new XmlSerializer(data.GetType()).Serialize(xmlWriter, data); 
      // } 

      // filterContext.Result = new ContentResult 
      // { 
      //  ContentType = "text/xml", 
      //  Content = UTF8.GetString(stream.ToArray()), 
      //  ContentEncoding = UTF8 
      // }; 
      //} 

      XmlDeclaration xmlDecl = new XmlDocument().CreateXmlDeclaration("1.0", "UTF-8", "yes"); 

      filterContext.Result = new ContentResult 
      {      
       ContentType = "text/xml", 
       Content = xmlDecl.OuterXml + data.ToString(), 
       ContentEncoding = UTF8 
      }; 
     } 
    } 
} 

Ainsi, la commenté pièce est le code que j'ai trouvé - voir les liens stackoverflow pour où je l'ai :)

Je remplace la méthode ToString() sur tous mes objets métier pour renvoyer une chaîne représentant la façon dont l'objet métier aimerait se représenter en tant que xml. La WCF accomplit ceci par des attributs, mais je voulais une solution plus propre qui ne reposait pas sur la réflexion ET je ne voulais pas avoir un projet de site Web et un projet WCF - le problème avec deux projets est qu'il était difficile de les garder tous les deux en synchronisation avec la fonctionnalité - j'obtiendrais des demandes comme "pourquoi le service ne me permet-il pas de filtrer mes résultats comme le fait le site?"

Je suis très intéressé par d'autres commentaires de cette approche :)

Voici un exemple d'un objet métier:

public class ContentFile : Entity 
{ 
    public ContentBook BelongsToBook { get; set; } 
    public string FileName { get; set; } 
    public XElement FileXml { get; set; } 
    public Binary FileData { get; set; } 
    public List<ContentFile> Versions { get; set; } 
    public List<ContentNode> ContentNodes { get; set; } 

    public override string ToString() 
    { 
     return this.ToString(SaveOptions.DisableFormatting); 
    } 

    public string ToString(SaveOptions options) 
    { 
     XElement xml = XElement.Parse("<contentFile id=\"" + Id.ToString() + "" + "\" />"); 
     xml.Add(new XElement("fileName", FileName)); 
     xml.Add(new XElement("fileStructure", FileXml)); 
     xml.Add(base.ToString(options)); 
     return xml.ToString(options); 
    } 
} 
2

Vous pouvez utiliser OData pour votre application MVC pour gérer Xml/JSON Je sais que d'autres personnes ont suggéré de rouler les vôtres - et c'est ce que je fais actuellement ... en utilisant mon propre ActionFilter ou ViewResult personnalisé

Exemple de code OData: Scott Hanselman's OData + StackOverflow blog post