views:

7602

answers:

5
+14  Q: 

ASP.NET MVC and WCF

I'm working my way into MVC at the moment, but on my "To learn at some point" list, I also have WCF.

I just wonder if WCF is something that should/could be used in an MVC Application or not? The Background is that I want a Desktop Application (.NET 3.5, WPF) interact with my MVC Web Site, and I wonder what the best way to transfer data between the two is. Should I just use special Views/have the controllers return JSON or XML (using the ContentResult)?

And maybe even more important, for the other way round, could I just call special controllers? Not sure how Authorization would work in such a context. I can either use Windows Authentication or (if the Site is running forms authentication) have the user store his/her credentials in the application, but I would then essentially create a HTTP Client in my Application. So while MVC => Application seems really easy, Application => MVC does seem to be somewhat tricky and a possible use for WCF?

I'm not trying to brute-force WCF in this, but I just wonder if there is indeed a good use case for WCF in an MVC application.

+6  A: 

You could use ADO.NET Data Services to share your data with either JSON (for JavaScript clients) or XML (for desktop applications).

ASP.NET MVC then can take advantage of this by using either of two in the model. As you probably know ADO.NET Data Services is based on WCF so you was on the right track.

jaircazarin-old-account
+3  A: 

Considering ASP.NET MVC is already pretty RESTful, using WCF alongside it would mean a lot of duplicated functionality. I would start with learning how to modify your output depending on your request type in ASP.NET MVC.

From there I would learn how to create a REST WADL from your ASP.NET MVC app, which I'm not sure is possible to do automatically at the moment. This way your C# application can communicate with your web app via the WADL.

Nicholas
I think perhaps you are making too many assumptions about his intentions. WCF and MVC solve two completely different problems, so suggesting that you're going to duplicate code by making use of both would only imply that he might use them incorrectly or inefficiently. I'm not sure why this answer has been voted as "correct"...
Nathan Ridley
Nathan is right.
tobias
+18  A: 

WCF services might make sense in this situation, but don't create services that align with your UI, create services that align with the business processes. ie. you won't have a service that returns the view data for each page, you will have a service that exposes logical operations. Then, your site can call the same services that the windows client calls, but you don't have to couple the design of the windows client to the design of the web site.

Instead of this:

Windows Client -> Services -> Web Site

It should be:

Windows Client -> Services

Web Site -> Services

jezell
+4  A: 

I use asp.net mvc as both my html website (default view engine) and my service endpoint. The service endpoint is used by my WPF and Silverlight clients by injecting "content-type=text/xml" into the header of a WebClient request (see ScottGu's post on consuming a service in SL which inspired this approach). I found somewhere on the net, some code that overrides the OnActionExecuted event like this:

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

So, the commented out piece is the code that I found - see the stackoverflow links for where I got it :)

I overrode the ToString() method on all of my business objects to return string representing how the business object would like to represent itself as xml. WCF accomplishes this via attributes, but I wanted a cleaner solution that didn't rely on reflection AND I didn't want to have both a website project and a WCF project - the problem with two projects is that it was hard to keep them both in sync with respect to functionality - I would get requests like "why doesn't the service allow me to filter my results like the website does?"

I'm very interested in other's feedback on this approach :)

Here's an example of a business object:

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);
    }
}
A: 

You could use OData for your MVC application to handle Xml/Json type stuff. I know other people have suggested roll your own - and this is what I'm currently doing .. via the use of my own custom ActionFilter or custom ViewResult.

Sample OData code: Scott Hanselman's OData + StackOverflow blog post.

Pure.Krome