I have a silverlight application which has a WCF in it.
Since it is a self hosted WCF I've understand I have to add an interface something like:
[ServiceContract]
public interface IPolicyRetriever
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
Stream GetFlashPolicy();
}
and the implemetation:
Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
public Stream GetSilverlightPolicy()
{
string result = #"<?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
return StringToStream(result);
}
public Stream GetFlashPolicy()
{
string result = #"<?xml version=""1.0""?>
<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
<cross-domain-policy>
<allow-access-from domain=""*"" />
</cross-domain-policy>";
return StringToStream(result);
}
but I don't understand the next steps I have to do in order the silverlight calls to WCF will not raise communcation exception.
Can you please show me the code I have to write and where?
(when I google it I didn't understand when the WCF calls to retrive the clientaccesspolicy, and what is the endpoint I have to add, I'm new to silverlight and WCF and don't know exaclty why I have to add an endpoint...)
this is my ServiceReference.ClientConfig:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMapService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:4693/MapService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMapService" contract="MapService.IMapService"
name="BasicHttpBinding_IMapService" />
</client>
</system.serviceModel>
</configuration>
thank you!
Silverlight Http stack (HTTP clientaccesspolicy.xml)
Must be hosted in root of your target domain. Could be easily checked with web browser.
Silverlight checks it automatically one time.
Silverlight 3 sockets (Custom policy server)
I've already made this policy server for Silverlight for Log2Console app.
I think this code may help SL Policy Server.
It has to be hosted on special port TCP port 943.
Silverligt 4 sockets (by default as in SL3, but can be opted-in for HTTP)
Set the SocketAsyncEventArgs.SocketClientAccessPolicyProtocol property on the SocketAsyncEventArgs passed to Socket.ConnectAsync to SocketClientAccessPolicyProtocol.Http.
Silverlight possible ports range
80, 443, 4502-4532 (if allowed in clientaccesspolicy.xml)
Detailed documentation
Related
I've built a WCF Publish Subscribe Topic Service and can successfully publish/subscribe with a console appplication (meaning I know it at least works in a console), and can successfully add both service references to both in my Silverlight Application.
The Problem:
Every time I try to subscribe or publish (in other words, anytime, I pass through my user name and password) while using Silverlight, the ServiceSecurityContext.Current.PrimaryIdentity is NULL, but it works fine in the console. Also, when accessing the service, it doesn't hit my custom user name and password validator when accessing it from Silverlight, but it does from a console.
What are my requirements?
I need to consume my publish subscribe service via Silverlight. The WCF Service needs to user UserName authentication. The WCF Service needs to be as secure as possible while still allowing for use with Silverlight. I have to use .Net, I have to use WCF PubSubTopic, I have to use Silverlight.
I am open to creating multiple subscriber endpoints(for instance, maybe a custom one for SL to use, and another for my api users), but I need to user the same publisher as the rest of my api users (oh yeah, btw, the WCF service is built as an api for my users to access if they want... I'm only allowing them access to the subscriber, and blocking the publisher)
I'm looking for example, advice, and/or troubleshooting help with my current problem. Here's some of my code
VB.NET code of Silverlight trying to publish something
Private Const PUBLISHER_ENDPOINT_ADDRESS As String = "http://myserver/portal/api/v1/Publisher.svc"
Friend Shared Sub PublishSomething()
Dim binding As PollingDuplexHttpBinding = New PollingDuplexHttpBinding()
Dim endpoint_address As EndpointAddress = New EndpointAddress(PUBLISHER_ENDPOINT_ADDRESS)
Dim client As New PublisherClient(binding, endpoint_address)
client.ClientCredentials.UserName.UserName = String.Format("{0}\{1}", Common.CompanyName, Common.UserName)
client.ClientCredentials.UserName.Password = "mypassword"
Dim uUpdate As New PortalPublisherService.UserUpdatedNotification
uUpdate.CompanyID = CompanyId
uUpdate.CompanyName = CompanyName
uUpdate.isAdvisor = True
uUpdate.isMaster = True
uUpdate.MetaNotes = "Testing from silverlight."
uUpdate.updateById = UserId
uUpdate.updateByName = UserName
uUpdate.userEmail = "bill#domain.com"
uUpdate.userId = UserId
client.UserUpdateAsync(uUpdate)
End Sub
Here's the web.config from the service
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<protocolMapping>
<add scheme="http" binding="wsDualHttpBinding"/>
</protocolMapping>
<extensions>
<bindingExtensions>
<add name="pollingDuplexHttpBinding"
type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement,
System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<!--primary behavior-->
<behavior name="Portal.Api.Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<serviceCertificate findValue="PortalApiCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Portal.Web.UserPassAuth, Portal.Web"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<pollingDuplexHttpBinding>
<binding name="pollingBindingConfig"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:01:00"
transferMode="Buffered"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="5242880"
maxBufferSize="655360"
maxReceivedMessageSize="655360">
<readerQuotas maxDepth="32"
maxStringContentLength="81920"
maxArrayLength="163840"
maxBytesPerRead="16384"
maxNameTableCharCount="163840" />
<security mode="TransportCredentialOnly" />
</binding>
</pollingDuplexHttpBinding>
</bindings>
<services>
<!--publisher endpoint configuration settings-->
<service behaviorConfiguration="Portal.Api.Behavior" name="Portal.Web.Publisher">
<endpoint address="" binding="pollingDuplexHttpBinding" contract="Portal.Publisher.IPublisher" bindingConfiguration="pollingBindingConfig"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="meta"/>
<host>
<baseAddresses>
<add baseAddress="http://server/portal/api/v1/IPublisher"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
I want to emphasize that I've tried, figuratively, a million different configurations, but can't remember every combination I've tried. I know I'm doing some stuff in the config I shouldn't be, but I was just trying to get it to work period. Also, here are the links I've looked at already
this one
and this one
there's more, but ... well... it's been a long day...
Thanks in advance for any help
Additional NOTE:
This is the binding I'm successfully using with NON-Silverlight implementations
<wsDualHttpBinding>
<binding name="Portal.Api.Binding" maxReceivedMessageSize="2147483647" sendTimeout="00:10:00">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false"/>
</security>
</binding>
</wsDualHttpBinding>
Since no one has answered this, I will answer this with my findings. What I'm looking for here is not possible with RIA services and Silverlight over HTTPS. WCF RIA services just don't offer this functionality at this time. If you know this statement not to be true.. please answer my question above with a solution.
It seems like I've been banging my head with custom faults in my Silverlight WCF service forever so I will happily DO MY BEST TO BUY A BEER for anyone who can help me solve this!!!
After much pain I finally have my WCF service throwing custom errors (ParameterValidationFault) and using Fiddler I know that the service's response contains my serialized fault object, but the HTTP response code is 500, not 200, so the client starts throwing exceptions rather than reading the response.
I know my SilverlightFaultBehavior class is supposed to take care of changing the response status code, but the breakpoints I set there are never being hit, so I'm hoping this is a simple web.config issue (web.config at end of post).
If this is relevant my web.config shows "the element 'behavior' has invalid child element 'silverlightFaults'...", in the section
<endpointBehaviors>
<behavior name="SilverlightFaultBehavior">
<silverlightFaults/>
</behavior>
</endpointBehaviors>
but I thought this wasn't a problem as I can view the service's metadata without error. However now I'm thinking this is the missing link that's preventing my status code from being changed on the way out. I have read that this error indicates a problem with the type attribute within my behaviorExtension element not exactly matching what .NET thinks it should be, but I have checked this a million times and the namespace and assembly name are definitely correct. I haven't messed with the version, culture, or public key stuff.
Is there a simple way for .NET to tell me exactly what this type string should be (spaces, commas, and all)? I have viewed the dll's properties in explorer but I'm still no closer.
Any other suggestions on where this might be coming from would be hugely appreciated.
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="silverlightFaults" type="my.namespace.SilverlightFaultBehavior, AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="SilverlightFaultBehavior">
<silverlightFaults/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="my.namespace.IService.customBinding0">
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="my.namespace.IService">
<endpoint address="" binding="customBinding" bindingConfiguration="my.namespace.IService.customBinding0" contract="my.namespace.IService" behaviorConfiguration="SilverlightFaultBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
My SilverlightFaultBehavior class starts like this and is a copy-paste of this MSDN post with a namespace change
namespace my.namespace
{
public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
{
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
OK so this problem has not been resolved but worked-around. I finally saw in this very useful post that I can have anonymous endpointBehaviors. The behaviour is now applied and custom faults are correctly (in a non-standard kind of way) returned as HTTP 200s. Making the behavior anonymous means it is applied to all endpoints, but as my service currently only needs a single endpoint this works for me.
It truly sucks that I had all this grief after reading the friggin manual and implementing it word for word. In the end my config parse error "the element 'behavior' has invalid child element 'silverlightFaults'..." was irrelevant, but a very smelly red-herring along the way as it very well could have been the cause (and still may be).
In case anyone is wondering, I just drank the beer.
My Silverlight/WCF application uses PrincipalPermission in each service method to ensure the user is Authenticated. This works just fine when I have everything configured to HTTP, but once I configured my service endpoints/bindings to support HTTPS (SSL), I get an exception thrown when I call the Demand() method of my PrincipalPermission object.
EDIT: I should mention I am using IIS 7.5 Express to host and debug this project.
Here is the method that checks to make sure the user is authendicated. It's called from each of my service methods:
protected void SecurityCheck(string roleName, bool authenticated)
{
System.ServiceModel.Web.WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
PrincipalPermission p = new PrincipalPermission(null, roleName, authenticated);
try
{
p.Demand();
}
catch (Exception ex)
{
/* wrap the exception so that Silverlight can consume it */
ServiceException fault = new ServiceException()
{
/* Code = 1 will mean "unauthenticated!" */
Code = 1, Message = ex.Message
};
throw new FaultException<ServiceException>(fault); }
}
}
The execption thown is "Request for principal failed."
Here are the important bits of my web.config file:
<behavior name="BinarySSL">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="6553600"/>
<serviceTimeouts transactionTimeout="00:10:00"/>
</behavior>
<binding name="MyApp.Web.Services.ProjectService.customBinding0"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<binaryMessageEncoding />
<httpsTransport authenticationScheme="Basic"/>
</binding>
<service name="MyApp.Web.Services.ProjectService" behaviorConfiguration="BinarySSL">
<endpoint address="" binding="customBinding" bindingConfiguration="MyApp.Web.Services.ProjectService.customBinding0"
contract="MyApp.Web.Services.ProjectService" />
</service>
Here is the ClientConfig:
<binding name="CustomBinding_ProjectService">
<binaryMessageEncoding />
<httpsTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<endpoint address="https://localhost:44300/Services/ProjectService.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ProjectService"
contract="ProjectProxy.ProjectService" name="CustomBinding_ProjectService" />
I'm hoping someone can point in in the right direction here. Again, this configuration works just fine until I configure my services for SSL. Any thoughts?
Thanks,
-Scott
I thought I found the problem, and answered my own question - but I was wrong. Still have the same issue.
I have no trouble retrieving a large amount of data, but sending it back to the service displays this error. I've tried adding the element to both the web.config and servicereferences.clientconfig and it's not recognized in either. At one point I got a message about adding readerQuotas to bindingElementExtensions, but I can't find anything useful on how to do this. I found posts saying I had to modify the devenv.exe.config and such, but doing that hosed VS.
Edit
Here's the binding section of the web.config:
<bindings>
<customBinding>
<binding name="QaRiM.Web.Service1.customBinding0">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="QaRiM.Web.Service1">
<endpoint address="" binding="customBinding" bindingConfiguration="QaRiM.Web.Service1.customBinding0"
contract="QaRiM.Web.Service1" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
and the servicereferences.clientconfig:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_Service1">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:36533/Service1.svc" binding="customBinding"
bindingConfiguration="CustomBinding_Service1" contract="ServiceReference1.Service1"
name="CustomBinding_Service1" />
</client>
</system.serviceModel>
</configuration>
Both were generated by VS.
You are simply missing the configuration for the maximum string content length.
Add this to your binding attributes (client and server)
<readerQuotas maxStringContentLength="2147483647" />
Sorry, I didn't realize that this child element is located under the encoding being used when using a custom binding, it appears to bebinaryMessageEncoding in your example. If not, try the other encodings with the setting.
<bindings>
<customBinding>
<binding name="QaRiM.Web.Service1.customBinding0">
<binaryMessageEncoding>
<readerQuotas maxStringContentLength="2147483647"/>
</binaryMessageEncoding>
</binding>
</customBinding>
</bindings>
if The maximum string content length quota (8192) has been exceeded while reading XML data.” is ignoring your web.config settings EVEN after you set
you can also solve the problem in your code by creating an instance of XmlDictionaryReaderQuotas and setting the MaxStringContentLength to 2147483647
then just use the instance of XmlDictionaryReaderQuotas seen here as mycreatedreaderquota
XmlDictionaryReaderQuotas mycreatedreaderquota = new XmlDictionaryReaderQuotas();
mycreatedreaderquota.MaxStringContentLength = 2147483647;
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, mycreatedreaderquota);
edit: This saved an incomplete draft, sorry
Synchronizing the service/client definitions is what you've done but it's definitely imperative that they match.
Are you sure you need custom binding? Have you tried using ws(Dual)HttpBinding as a base?
This post may be of interest: silverlight 3 wcf service configuration -- getting maxreceivedmessagesize error, specifically the httpRuntime maxRequestLength="2147483647" setting.
You may need to set maxBufferPoolSize and maxItemsInObjectGraph. The config in the linked SO post pretty much maxed everything out.
I don't know if you use the ChannelFactory client proxy method or the service reference method but you may wish to go the former route. In debug sessions I was finding certain values from the config weren't being applied as I had thought but my short term memory on the subject is rather lost now.
Related to #5 somewhat, you can run into WCF Test Client issues where the test client is using default bindings that you're not prepared for.
Another post that may be of interest: http://www.haveyougotwoods.com/archive/2008/04/14/wcf-message-streaming.aspx
Streaming is likely your best bet on the client side to keep from the blocking nature of buffered transferMode. I don't know the specifics of how big the data will be consistently but your service will behave a little nicer on the client end if you went that route. A good primer on configuring just the client side for streaming can be found here: http://systemmetaphor.blogspot.com/2009/05/using-wcf-to-transfer-large-data-files.html.
Hopefully some combination of the above helps
Have you tried setting the maxStringContentLength within the config for the service? In my situation, setting it on the service allowed for the Silverlight client to use the desired value for maxStringContentLength.
One note is that if you are allowing longer strings, but don't adjust the maxReceivedMessageSize, than this can cause issues as well. The maxReceivedMessageSize does need to be controlled on both the service and the client, as one will not inherit the values from another.
I have created a very basic service operation that needs to write content to my database. This service looks like the following:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
public class myService : ImyService
{
public MyServiceResult MyMethod(string p1, string p2)
{
try
{
// Do stuff
MyResponseObject r = new MyResponseObject();
r.Property1 = DateTime.Now;
r.Property2 = "Some other data";
return r;
}
catch (Exception ex)
{
return null;
}
}
}
ImyService is defined as shown here:
[ServiceContract]
public interface ImyService
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped)]
MyServiceResult MyMethod(string p1, string p2);
}
This service will be exposed to both WP7 and iPhone client applications. Because of this, I believe I need to use webHttpBinding. This has caused me to use the following settings in my web.config file:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="myServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="myService">
<endpoint address=""
behaviorConfiguration="myServiceBehavior"
binding="webHttpBinding"
contract="ImyService" />
</service>
</services>
</system.serviceModel>
Both the service and WP7 app are part of the same solution. I can successfully add a reference to the service in my application. When I run the application though, the page that references the service throws an error. The error says:
Could not find default endpoint element that references contract 'MyServiceProxy.ImyService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
What am I doing wrong? It just seems like this should be a pretty straightforward thing. Thank you for your help.
Have you copied the file "ServiceReferences.ClientConfig" into your Windows Phone 7 project? This file is in your WCF project. Also, WP7 clients support basicHttpBinding only. So, you may see an empty "ServiceReferences.ClientConfig" file unless you switch over to basicHttpBinding