开发者

Simple WCF POST with Uri Template

I thought this would be incredibly simple, but I must be missing something. I am trying to make a simple WCF POST request in conjunction with a UriTemplate. I have read numerous examples where people use a stream paramater as the last paramater, and this is supposed to pick up the POST body. I can only get this to work if the stream is the only paramater.

I've gone back to basics with a simple Hello World service.

Here is my code on the client

static string Test()
{
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:1884/MyAPI/Service.svc/HelloWorld");
    req.Method = "POST";
    req.ContentType = "text/plain";
    Stream reqStream = req.GetRequestStream();
    byte[] fileToSend = System.Text.UTF8Encoding.UTF8.GetBytes("sometext");
    reqStream.Write(fileToSend, 0, fileToSend.Length);
    reqStream.Close();
    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
    var sr = new StreamReader(resp.GetResponseStream());
    return sr.ReadToEnd();
}

And this is the code on the service

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "HelloWorld")]
    Stream HelloWorld(Stream content);
}

public Stream HelloWorld(Stream content)
{
    var sr = new StreamReader(content);
    string text = sr.ReadToEnd();
    return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World! " + text)); 
}

This all works fine. Then I make this change:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "HelloWorld/test/{test}")]
    Stream HelloWorld(string test, Stream content);
}

public Stream HelloWorld(string test, Stream content)
{
    var sr = new StreamReader(content);
    string text = sr.ReadToEnd();
    return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World! " + text + test)); 
}

And change the client code to hit HelloWorld/test/sometext

I get a 500 Internal Server Error. I've trie开发者_如何学编程d about 10 different variations including using a ?key=value type UriTemplate, returning strings instead of streams etc, and no luck.

Feels like I'm missing some tiny little thing that is going to make this work, as I have seen countless examples of exactly this all over the web. Theirs works, mine doesn't.

Any ideas?


I am not sure what went wrong, but after trying everything, I resolved this by creating a new project and copying all the code over. Never worked out what the differences were, maybe something got corrupted

Edit: in the end we discovered we had to specify WebServiceHostFactory in the Service.svc. This was there by default in the new project


When streaming, the Stream must be the only parameter: http://msdn.microsoft.com/en-us/library/ms789010.aspx

You may be able to use message headers: Add filename and length parameter to WCF stream when Transfermode = Stream


You can use new single file WCF model to configure and adjust endpoint behaviour. I combined your contract and service class into one file to show you how to do this.

using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace StreamService
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class MergedEndpoint
    {
        [WebGet(RequestFormat = WebMessageFormat.Xml, UriTemplate = "Data/{someid}",
          ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
        public string GetData(string someid)
        {
            return string.Format("You entered: {0}", someid);
        }

          [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "HelloWorld",
          ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
        public Stream HelloWorld1(Stream content)
        {
            var sr = new StreamReader(content);
            string text = sr.ReadToEnd();
            return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World from single file! " + text));
        }
         [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "HelloWorld/test/{testparam}",
          ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
          public Stream HelloWorld2(string testparam, Stream content)
        {
            var sr = new StreamReader(content);
            string text = sr.ReadToEnd();
            return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World from single file! " + testparam+ text));
        }
    }
}

Input parameters need to be same name as method params. Their type is also string. You need to do the conversion if you want different input param.

You need to create WCf project and add Global.asax file with routing info for this file. You may need to add reference to System.ServiceModel.Activation to setup routing. Example:

protected void Application_Start(object sender, EventArgs e)
        {
 RegisterRoutes();
        }


        private void RegisterRoutes()
        {


            RouteTable.Routes.Add(new ServiceRoute("MergedEndpoint", new WebServiceHostFactory(), typeof(MergedEndpoint)));

    }

Your Client code has one change to content type.

 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:55166/MergedEndpoint/HelloWorld/test/234");
            req.Method = "POST";
            //req.ContentType = "text/plain";
            req.MediaType = "HTTP/1.1";
            req.ContentType = "application/json; charset=utf-8";
            Stream reqStream = req.GetRequestStream();
            byte[] fileToSend = System.Text.UTF8Encoding.UTF8.GetBytes("sometext");
            reqStream.Write(fileToSend, 0, fileToSend.Length);
            reqStream.Close();
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            var sr = new StreamReader(resp.GetResponseStream());
            string outp = sr.ReadToEnd();
            Console.WriteLine("Response:"+outp);

You can still read the raw content even if it is set to Json type.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜