Problem consuming a REST service from Silverlight
In my web project I have a TestStreamingService.svc file containing a REST service.
The service contract :
[ServiceContract(Namespace = "")]
public interface ITestStreamingService
{
[OperationContract]
[WebGet(UriTemplate = "Download?file={file}&size={size}")] //file irrelevant, size = returned size of the download
Stream Download(string file, long size);
[OperationContract]
[WebInvoke(UriTemplate= "Upload?file={file}&size={size}", Method = "POST")]
void Upload(string file, long size, Stream fileContent);
[OperationContract(AsyncPattern=true)]
[WebInvoke(UriTemplate = "BeginAsyncUpload?file={file}", Method = "POST")]
IAsyncResult BeginAsyncUpload(string file, Stream data, AsyncCallback callback, object asyncState);
void EndAsyncUpload(IAsyncResult ar);
}
The service implementation (the *.svc file)
using System; using System.IO; using System.ServiceModel; using System.ServiceModel.Activation; using ICode.SHF.Tests;
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class TestStreamingService : ITestStreamingService {
public Stream Download(string file, long size)
{
return new SHFTestStream(size);
}
public void Upload(string file, long size, Stream fileContent)
{
FileInfo f = new FileInfo(String.Format(@"C:\{0}", file));
using (FileStream fs = f.Create())
{
CopyStream(fileContent, fs);
fs.Flush();
fs.Close();
}
}
public IAsyncResult BeginAsyncUpload(string file, Stream data, AsyncCallback callback, object asyncState)
{
return new CompletedAsyncResult<Stream>(data, file);
}
public void EndAsyncUpload(IAsyncResult ar)
{
Stream data = ((CompletedAsyncResult<Stream>)ar).Data;
string file = ((CompletedAsyncResult<Stream>)ar).File;
StreamToFile(data, file);
}
private void StreamToFile(Stream data, string file)
{
string subDir = Guid.NewGuid().ToString("N");
string uploadDir = Path.Combine(Path.GetDirectoryName(typeof(TestStreamingService).Assembly.Location), subDir);
Directory.CreateDirectory(uploadDir);
byte[] buff = new byte[0x10000];
using (FileStream fs = new FileStream(Path.Combine(uploadDir, file), FileMode.Create))
{
int bytesRead = data.Read(buff, 0, buff.Length);
while (bytesRead > 0)
{
fs.Write(buff, 0, bytesRead);
bytesRead = data.Read(buff, 0, buff.Length);
}
}
}
}
public class CompletedAsyncResult : IAsyncResult { T data;
string file;
public CompletedAsyncResult(T data, string file)
{ this.data = data; this.file = file; }
public T Data
{ get { return data; } }
public string File
{ get { return file; } }
#region IAsyncResult Members
public object AsyncState
{
get { return (object)data; }
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get { throw new NotImplementedException(); }
}
public bool CompletedSynchronously
{
get { return true; }
}
public bool IsCompleted
{
get { return true; }
}
#endregion
}
My Web.Config
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors> 开发者_如何转开发
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="ICode.SHF.SL.Tests.Web.TestStreamingService.customBinding0"/>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
/>
<services>
<service name="ICode.SHF.SL.Tests.Web.TestStreamingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:40000/Streaming"/>
</baseAddresses>
</host>
<endpoint name="TestStreamingEndpoint" address="RESTService" binding="webHttpBinding" bindingConfiguration="ICode.SHF.SL.Tests.Web.TestStreamingService.customBinding0"
contract="ICode.SHF.SL.Tests.Web.ITestStreamingService" behaviorConfiguration="REST"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
I'm trying to consume the service from silverlight (the web project contains a clientaccesspolicy.xml) via a WebClient however I seem to fail, Fiddler doesn't show any calls being made.
(using WebClient.OpenWriteAsync (for upload) & OpenReadAsync (for download))
The uri used for the Client is : "http://localhost:40000/Streaming/Service/Download?file=xxx&size=65536"
When I use the following uri in IE : "http://localhost:40000/TestStreamingService.svc/Download?file=xxx&size=65536" a download operation begins and the downloaded file matches the size passed.
I'm not having success with the IE uri in the WebClient though.
Could anyone please explain to me what am I doing wrong? It seems I've missed something fundamental...
Do your site require authentication? As for fiddler, try connecting your webclient to:
http://localhost.:40000/Streaming/Service/Download?file=xxx&size=65536
(note the extra dot after localhost
)
It would appear that I've managed to solve my problem regarding the Downloading capability from Silverlight via. WebClient.
Here's what I did.
- Moved the service contract and implementation to a separate project MyWCFLibrary (WCF Service Library)
- Added a reference of the said library to the ASP.NET website hosting the project
Added a text file "Service.svc" and edited it :
<%@ ServiceHost Language="C#" Debug="true" Service="MyWCFLibrary.TestStreamingService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
Modified the WebClient operation's uri to match the *.svc file
Seems that it worked.
I'm still attemptring to figure one thing out, so comments are welcome :
I can perform an operation on the service via the Webclient like this :
WebClient wc = new WebClient();
string uri = String.Format("http://localhost.:40000/Service.svc/Download?file=xxx&size={0}", size);
wc.OpenReadAsync(new Uri(uri));
but not like this :
string uri = String.Format("http://localhost.:40000/Services/StreamingService/Download?file=xxx&size={0}", size);
wc.OpenReadAsync(new Uri(uri));
Where : localhost:40000/Services is the base address of the service and StreamingService is the address of the endpoint (latest changes in my WebConfig)
Can anyone explain why? or am I stuck with using the 1st uri by default?
精彩评论