WCF set Endpoint and Binding dynamically in code - wcf

Yes, I've read the other questions on SO, MSDN, and other sites, but I found no answers as clear as I can understand. I need to set my Silverlight application's WCF references relative to the site that it's loaded from, but I can't get it to work. There is no problem with the service itself, it is working. When I move from local to my real server, I get errors in my SL app complaining about not connecting to localhost.
Here is my ServiceReferences.ClientConfig file:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_AccountManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<binding name="CustomBinding_FileManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<binding name="CustomBinding_SiteManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:60322/AccountManager.svc"
binding="customBinding" bindingConfiguration="CustomBinding_AccountManager"
contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />
<endpoint address="http://localhost:60322/FileManager.svc" binding="customBinding"
bindingConfiguration="CustomBinding_FileManager" contract="FileManager.FileManager"
name="CustomBinding_FileManager" />
<endpoint address="http://localhost:60322/SiteManager.svc" binding="customBinding"
bindingConfiguration="CustomBinding_SiteManager" contract="SiteManager.SiteManager"
name="CustomBinding_SiteManager" />
</client>
</system.serviceModel>
</configuration>
Yes, I will optimize the buffer/message sizes and I know the possible DoS exploits, forget about it for now, I need them for big file transfers. An approach I tried is while instantiating the clients, I've used this code:
fileManager = new FileManagerClient(new BasicHttpBinding(), new EndpointAddress("http://" + Settings.Host + "/FileManager.svc"));
accManager = new AccountManagerClient(new BasicHttpBinding(), new EndpointAddress("http://" + Settings.Host + "/AccountManager.svc"));
where Settings.Host is my own method which returns me the host that the SL app is running from, tested, works. When I uploaded my XAP and tried, it still wanted to go for http://localhost:60322/AccountManager.svc, after further investigation, I've realized that there are still lots of references to localhost, in unseen files:
AccountManager.disco:
<?xml version="1.0" encoding="utf-8"?>
<discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">
<contractRef ref="http://localhost:60322/AccountManager.svc?wsdl" docRef="http://localhost:60322/AccountManager.svc" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
</discovery>
Parts of AccountManager.wsdl:
... <wsdl:import namespace="" location="http://localhost:60322/AccountManager.svc?wsdl=wsdl0" />...
...[lots of operation declarations]...
<wsdl:service name="AccountManager">
<wsdl:port name="CustomBinding_AccountManager" binding="tns:CustomBinding_AccountManager">
<soap12:address location="http://localhost:60322/AccountManager.svc" />
<wsa10:EndpointReference>
<wsa10:Address>http://localhost:60322/AccountManager.svc</wsa10:Address>
</wsa10:EndpointReference>
</wsdl:port>
</wsdl:service>
Part of AccountManager1.xsd:
<xs:import schemaLocation="http://localhost:60322/AccountManager.svc?xsd=xsd2" namespace="http://schemas.datacontract.org/2004/07/Leftouch.Data.Summary" />
Part of configuration.svcinfo:
<endpoint normalizedDigest="<?xml version="1.0" encoding="utf-16"?><Data address="http://localhost:60322/AccountManager.svc" binding="customBinding" bindingConfiguration="CustomBinding_AccountManager" contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />" digest="<?xml version="1.0" encoding="utf-16"?><Data address="http://localhost:60322/AccountManager.svc" binding="customBinding" bindingConfiguration="CustomBinding_AccountManager" contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />" contractName="AccountManager.AccountManager" name="CustomBinding_AccountManager" />
Part of Reference.svcmap:
</ClientOptions>
<MetadataSources>
<MetadataSource Address="http://localhost:60322/AccountManager.svc" Protocol="http" SourceId="1" />
</MetadataSources>
<Metadata>
<MetadataFile FileName="AccountManager2.xsd" MetadataType="Schema" ID="e473b2d5-7af3-4390-87c3-a4fc3f54fb96" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd2" />
<MetadataFile FileName="AccountManager1.xsd" MetadataType="Schema" ID="fd3a1ae0-b38b-4586-8622-5b0ee07e39fb" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd0" />
<MetadataFile FileName="AccountManager.xsd" MetadataType="Schema" ID="6a49ee64-6eac-40e2-bcff-26418435e777" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd1" />
<MetadataFile FileName="AccountManager.disco" MetadataType="Disco" ID="9ec9a8cc-0cf0-4264-a526-b5a6c08f7d36" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?disco" />
<MetadataFile FileName="AccountManager1.wsdl" MetadataType="Wsdl" ID="54a5b2c0-9d0e-4043-a7e4-d27ae6674bfc" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?wsdl=wsdl0" />
<MetadataFile FileName="AccountManager.wsdl" MetadataType="Wsdl" ID="f8923013-3a6c-412b-b7da-bee5a5a7bb64" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?wsdl" />
..and ALL these again for other 2 services too.
I am not a master of web services/bindings/endpoints/operation contracts or any related stuff. I just want to make my totally already-nice-working (when URI is hardcoded) system work for relative URIs, that's all I need. There must be a simple solution. Can someone explain what exactly those file types and declarations resemble, which are important and which are optional, and how can I create dynamic service references in the cleanest form. Please, with explanations. I've already seen lots of posts and articles about dynamic service bindings and references, but honestly, everything gets messed up and I end up not understanding anything from it. Any constructive criticism and solutions are welcome.

Is the config file for your service (not the client) using endpoints with fully qualified addresses (like your client config)? If so, the reason you're seeing all those localhost references is because when you add the service reference, it's going to carry through that address in the generated files.
Update the endpoint in your service config file to either use the fully qualified address on that machine (i.e., http://somname.com/service.svc), or set the baseAddresses in the config file to the machine name.
Additionally, if you're using WCF 4.0 (VS 2010/.NET 4.0), you can have WCF create a default endpoint for your service(s) by ommitting the endpoints from the config file altogether (as I understand it - we're just moving to 4.0 at work now, so I haven't played with the new features).
EDITED TO ADD
New approach, same basic idea (that the URI is being imported from somewhere). Based on your comments below, it sounds like your service's config is set up fine, with no hard-coded URIs pointing to localhost.
When you move your application to the target server(s), are you updating your reference to your service (via the Add Service Reference) as well, or simply moving the files that generates from your local box to the target server?
If you are, I'm wondering if that might be the source of your problem. I would think that specifying the service address when you create the client should override anything in the WSDL-related files, but maybe its not.
Something to try:
Delete the <client> section from your Web.config. Then, when you create the client, do so like this:
fileManager = new FileManagerClient(new BasicHttpBinding("CustomBinding_FileManager"), new EndpointAddress("http://" + Settings.Host + "/FileManager.svc"));
Make sure you pass in the name of the binding configuration section in the BasicHttpBinding constructor, otherwise you'll get the binding with the default values, not the larger values you specified.
The idea here is to eliminate any chance that the client config file settings are overriding what you're passing in on the FileManagerClient creation.
I'd consider it less than ideal to have to update the service reference for every deployment to each individual server - what you're trying to accomplish makes sense. I do something similar in an n-tier app I've written - the only difference is that I don't use service references, I generate the proxy via SvcUtil and then generate channels via ChannelFactory<T>, which is another route you might want to look at.
If none of this help, please feel free to e-mail me (my e-mail address is in my profile) - it might be easier to figure this out via e-mail exchange and then post the final solution.

Related

Getting "EndPoint Not Found" error with WCF service deployed to SharePoint 2010 site

I am trying to utilize the autocompleteextender from the ajaxcontroltoolkit in one of my sharepoint solutions (which requires an older version of the library since all of the recent ones require the .NET Framework 4.0) and unfortunately I can't use a page method in a UserControl, only in an actual page. Therefore I am left with only the one option which is to use a method from an actual web service. The problem is that I can't seem to figure out how to correctly deploy the service and configure the web.config. When I try to view the metadata information in the browser I get an error message saying "endpoint not found". However, when I try to enter the URL with the name of a method appended to the URL it actually finds AND executes the method returning JSON data -which obviously means that it can find my service. Also, I can use jQuery to call my service and return the JSON data -but I don't want to use jQuery for this project and would rather just keep everything pure C#.
What I want to know is, why can't I get the "pretty metadata information" to display in the browser so I get the "warm fuzzy" and allow the proper discovery of the service by other applications the way it should be working?
I triple checked the web.config and I have both the metadataExchange endpoint as well as the one that references my service both entered and I have httpGetEnabled set to "true". I tried running svcutil /t:metadata and pointed it to my service but I get several errors, the first telling me that it can't obtain the metadata, the second that the Metadata contains a reference that cannot be resolved and the third is an HTTP GET Error that says the HTML document does not contain Web service discovery information. Even though I have my svc file in the same ISAPI directory as the OOTB SharePoint services and can generate the XSD files for those services but not for mine.
Here is what my current web.config file looks like...
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" />
<identity impersonate="true"/>
</system.web>
<system.serviceModel>
<!-- we need this to enable session -->
<client>
</client>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataSupportBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://myserver/sites/mysitecollection/_vti_bin/WebServices/MyService.svc" policyVersion="Policy15"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="false"/>
<serviceCredentials>
<windowsAuthentication includeWindowsGroups="true" />
</serviceCredentials>
</behavior>
<behavior name="defaultBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
</bindings>
<services>
<service behaviorConfiguration="metadataSupportBehavior" name="Sample.WebServices.MyService">
<clear />
<endpoint address="" binding="basicHttpBinding" contract="Sample.WebServices.IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange">
<identity>
<certificateReference storeName="My" storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://myserver/sites/mysitecollection/_vti_bin/WebServices/MyService.svc" />
</baseAddresses>
</host>
</service>
</services>
I'm at a real loss here. Any thoughts?
Thanks in advance!!!
UPDATE #1: OK, I almost got it working. I mean I "technically" did but only in the browser and with a few caveats.
The first thing I did was add the following code to my web.config file:
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
And then updated my service endpoint to include a reference to the new configuration like so:
<endpoint address="" binding="webHttpBinding" contract="Sample.WebServices.IMyService" behaviorConfiguration="webBehavior">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
I also changed the binding from basicHttpBinding to webHttpBinding.
Now for the caveats...
I can get it to fully function and return an XML response in the browser but ONLY if I run the service in debug mode, which means that it's being hosted in Visual Studio and not IIS so it doesn't really count.
When I don't run the service in debug mode I get an error that says something to the effect of "The exception message is 'Value cannot be null. Parameter name: source'".
After stepping through my code in the debugger I see the real error which is:
Request for the permission of type 'IBM.Data.DB2.DB2Permission, IBM.Data.DB2, Version=9.0.0.2, Culture=neutral, PublicKeyToken=7c307b91aa13d208' failed.
Which in simple English means that I am trying to load a 32-Bit version of the IBM.Data.DB2 DLL in my SharePoint site that unfortunately only allows 64-Bit assemblies.
So my first reaction is "Ah ha!" this should be simple right? I mean I either need to find a 64bit version of the DLL or just configure the Application Pool that my SharePoint site in IIS uses to allow 32bit assemblies to be loaded and everything should be peachy! Aren't I smart? But NO says SharePoint! Not only am I not going to let you do either of those things* but I'm going to completely render your entire SharePoint farm unusable for even attempting to implement such ludicrous solutions!!!
So now when I try to navigate to any resource within my SharePoint farm I'm greeted with this.
[NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.Office.Server.Administration.UserProfileApplicationProxy.get_ApplicationProperties() +134
Microsoft.Office.Server.Administration.UserProfileApplicationProxy.get_PartitionIDs() +44
Microsoft.Office.Server.Administration.UserProfileApplicationProxy.IsAvailable(SPServiceContext serviceContext) +329
Microsoft.Office.Server.WebControls.MyLinksRibbon.get_PortalAvailable() +44
Microsoft.Office.Server.WebControls.MyLinksRibbon.EnsureMySiteUrls() +60
Microsoft.Office.Server.WebControls.MyLinksRibbon.get_PortalMySiteUrlAvailable() +15
Microsoft.Office.Server.WebControls.MyLinksRibbon.OnLoad(EventArgs e) +91
System.Web.UI.Control.LoadRecursive() +65
System.Web.UI.Control.LoadRecursive() +190
System.Web.UI.Control.LoadRecursive() +190
System.Web.UI.Control.LoadRecursive() +190
System.Web.UI.Control.LoadRecursive() +190
System.Web.UI.Control.LoadRecursive() +190
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2427
Even if I undo all of my changes to IIS, the App Pool, the DLLs, restart IIS, restart my server etc. nothing works. I'm just totally screwed.
Good times.
*Well to be fair SharePoint had nothing to do with the 64-Bit IBM driver being unavailable but I'm just gonna assume that even if there was one that I could techically use that SharePoint would find a way to punish me for trying to get any work done.
UPDATE #2: OK, I fixed the whole "SharePoint site not working thing". Basically the Application Pools in use for all SharePoint related sites seemed to have changed to enable 32-Bit applications, including the SecurityTokenServiceApplication (kudos to the dude over at this site for not only having the same problem but also posting the solution). Now while I don't remember specifically setting the value to true for every SharePoint related Application Pool I'm willing to play along and say that perhaps in an act of desperation I may have just said to hell with it and started recklessly changing configuration settings. You know, because that's just what seasoned developers do.
Anyhow...
Now my Central Administration website is back up and running but the UserProfileApplication service is still wonky and I am still inclined to think that my SecurityTokenServiceApplication service is still on the fritz since I get an error (details hidden of course since the web.config is configured to do just that) telling me that "The server was unable to process the request due to an internal error".
Details to follow...
UPDATE #3: OK, I got everything back to it's original working form. I confirmed that merely enabling 32-Bit applications for one Application Pool used by a SharePoint resource effectively updates all the other ones to follow suit. I know this for a fact because I positively did not change that value for EVERY SharePoint related Application Pool myself. I would have remembered going through something like that. As it turns out all of those Application Pools with the funky looking "GUID-like" names that the SharePoint Web Services use were also all updated to allow 32-Bit applications to run which is what caused my environment to go all screwy.
In addition, I got my SecurityTokenService to display it's metadata in the browser correctly by following the suggestions provided here. Although they seem like a bit of a "hack", they are small and reversable hacks so I'm game.
In short, you edit the config files for each service like so:
In the spStsActAsBinding binding rename httpTransport to httpsTransport.
Add allowInsecureTransport=”true” and enableUnsecuredResponse=”true” to the binding security.
Ensure that you define only 1 binding configuration (for example in Profile Service, you will find 2 binding configuration for the same service each for http and https protocol).
After doing all this you should be able to get the "warm metadata fuzzy" that I'm trying to get for the custom WCF service I'm working on.
So now I just need to get back to fixing my initial problem which was to get the 32-Bit version of the IBM.Data.DB2 DLL to work with SharePoint 2010. The one thing I haven't tried yet is creating an IIS hosted service that runs COMPLETELY independent of SharePoint. Doing this would allow me to create a separate Application Pool that CAN in fact run 32-Bit applications without causing SharePoint to flip out -hopefully.
UPDATE #4: OK, so first of all I am going to tell you to ignore my advice above about messing around with the SecurityTokenService. Sure you get the "warm metadata fuzzy" with the changes but then you'll probably cause your SharePoint site's to break.
So anyway...I have now created a site that is totally independent of SharePoint that uses it's own Application Pool that is configured to allow 32-Bit applications so that technically should take care of all of my issues. Well, when I try typing text into my textbox it does not "autocomplete" but there is network activity happening because I see it in Fiddler. The strange part is that it only happens once. Meaning, if I hit backspace and retype something else no additional calls are made to the web service. I have to reload the page to test it out again. The error message I get when it does call the method is "405 Method Not Allowed". Now my method interface signature uses WebInvoke with the Method property set to "GET" which I've been told should work fine and has in the past when making REST calls that return JSON data, only now it doesn't work. Oh, in the web browser it works and I see wonderful XML results returned from the method. But when I try to use the AutoCompleteExtender in my SharePoint UserControl to call the method (or using any other client for that matter) it doesn't. I have tried using the WebGet() attribute but then nothing is returned in the web browser either. I think I got a 415 error for that one.
UPDATE #5: I found another post where some guy seems to be having the exact same problem that I am having now, only difference is that I can't get the autocomplete to work even if I have the webservice in the same project. I also tried the suggestions that were made in his post and they didn't work either. Here is a link to the post for those interested.
For webpart project (with ASCX) you can:
1) Enable Anonymous Authentication for SP SIte in IIS
2) Add SP Mapped folder ISAPI
3) Create YourService.asmx in ISAPI
<%# WebService Language="C#" Class="YourNamespace.YourService, YourAsm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=YourPublicKeyToken"%>
4) Edit user control code:
public partial class YourControl : UserControl
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
FixFormAction();
CheckScriptManager();
EnsureUpdatePanelFixups();
}
private void FixFormAction()
{
// Fix problem with postbacks and form actions (DevDiv 55525)
Page.ClientScript.RegisterStartupScript(GetType(), ID, "_spOriginalFormAction = document.forms[0].action;", true);
// By default, the onsubmit event for forms in SharePoint master pages call "return _spFormOnSubmitWrapper()"
// which blocks async postbacks after the first one. Not calling "_spFormOnSubmitWrapper()" breaks all postbacks
// and defeats the purpose of _spFormOnSubmitWrapper() which is to block repetitive postbacks.
// To call _spFormOnSubmitWrapper() and allow partial postbacks, remove "return" from the original call.
if (Page.Form != null)
{
string formOnSubmitAtt = Page.Form.Attributes["onsubmit"];
if (formOnSubmitAtt == "return _spFormOnSubmitWrapper();")
{
Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();";
}
}
}
private void EnsureUpdatePanelFixups()
{
if (this.Page.Form != null)
{
var fixupScript = #"
_spBodyOnLoadFunctionNames.push(""_initFormActionAjax"");
function _initFormActionAjax()
{
if (_spEscapedFormAction == document.forms[0].action)
{
document.forms[0]._initialAction = document.forms[0].action;
}
}
var RestoreToOriginalFormActionCore = RestoreToOriginalFormAction;
RestoreToOriginalFormAction = function()
{
if (_spOriginalFormAction != null)
{
RestoreToOriginalFormActionCore();
document.forms[0]._initialAction = document.forms[0].action;
}
}
";
ScriptManager.RegisterStartupScript(this, this.GetType(), "EnsureUpdatePanelFixup", fixupScript, true);
}
}
private ScriptManager CheckScriptManager()
{
ScriptManager sm = ScriptManager.GetCurrent(Page);
if (sm == null)
{
if (Page.Form != null)
{
sm = new ScriptManager();
sm.ID = Page.Form.ID + "_ScriptManager";
Page.Form.Controls.Add(sm);
//Page.Form.Controls.AddAt(0, sm);
}
}
sm.EnablePageMethods = true;
var sharedPath = #"~/_layouts/Share/";
var path = #"~/_layouts/YourWebPart/";
sm.Scripts.Add(new ScriptReference { Path = #"/_vti_bin/YourService.asmx/JS" });
//Registering ExtJS
Page.ClientScript.RegisterClientScriptInclude(GetType(), "ext-all", sharedPath + "scripts/ext-all.js");
ScriptManager.RegisterClientScriptBlock(this, GetType(), "ext-css",
"<link href='" +
sharedPath + "resources/css/ext-all.css' rel='stylesheet' type='text/css' />", false);
Page.ClientScript.RegisterClientScriptInclude(GetType(), "YourScript", path + "scripts/Script.js");
return sm;
}
}
5) Edit your service code:
[WebService(Namespace = "http://tempuri/ws")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class YourService : WebService
{
//[WebMethod]
[ScriptMethod]
[WebMethod(EnableSession = true)]
//[ScriptMethod(UseHttpGet = true)]
public string YourWebMethod(string arg)
{
return arg;
}
}
6) Use you web service methods in control javascript:
YourNamespace.YourService.YourWebMethod(arg, function (result) {
if (result) {
if (typeof result == 'string') {
alert(result);
}
}
}, function (error) { alert('YourWebMethod failed! ' + error.get_message()); });
}
No webconfig
For svc in ISAPI subfolder
<%# ServiceHost Debug="true" Language="C#"
Service="Namespace.MyService, MyAsm, Version=1.0.0.0, Culture=neutral, PublicKeyToken=MyPublicKeyToken"
%>
web.config can be:
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2097151"/>
</requestFiltering>
</security>
</system.webServer>
<system.web>
<httpRuntime executionTimeout="60" maxRequestLength="2097151" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyHttpBinding"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
<readerQuotas maxArrayLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CustomServiceBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service behaviorConfiguration="CustomServiceBehaviour" name="Namespace.MyService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="MyHttpBinding" contract="Namespace.IMyService" bindingNamespace="http://tempuri/ws" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
So I still can't get the autocompleteextender to work with my WCF service but I did figure out how to fix the EndPoint Not Found error.
So there are three things at play here that I didn't fully understand or overlooked.
The WCF Client Test Utility from Microsoft only tests SOAP requests.
How all of the different bindings worked and what they meant.
That you need to make sure the right account is being used for the Anonymous User Identity in IIS.
With items #1 and #2 I needed to add another endpoint to handle soap requests that either used basichttpbinding or wshttpbinding. I had only one binding specified that was webhttpbinding and although that gave me the warm fuzzies in the browser it essentially caused the WCF Client Utility not to work because I basically didn't have any SOAP endpoints defined. Read more about the differences here.
As for item #3, I found my answer here. It took days of weaving through posts about changing the web.config, writing stuff in code with usernames and passwords to enabling and disabling every form of authentication type known to man in IIS. This was what ultimately did the trick and allowed me to use the WCF Client Test Utility without the pesky EndPoint Not Found error.
Also, for those of you that are interested, I've actually started a new post that focuses specifically on the ajaxcontroltookkit autocompleteextender issue that can be found here.
FYI: I have managed to get to the point where I can return identical JSON data from my WCF service that looks just like the JSON data that gets returned when the code is executed from the ASPX's CodeBehind page and actually works...but for some reason when using the WCF method nothing gets autocompleted. The only thing I notice that's different when using the WCF service method is that before getting the sweet http 200 message with the JSON data there is always an http 401 authentication error that precedes it.

Consume WCF service (using MSMQ) with legacy client

I created a WCF service which uses MSMQ.
Multiple .NET clients should be able to consume this service and send messages to it.
Partially the clients are written in .NET versions where there was no WCF (e.g. .NET 1.1).
For these clients I make direct use of the Msmq API.
The problem is, that the encoding of the messages don't fit the expected encoding on the service-side.
So I tried to alter the message encoding on the service-side using a customBinding:
<bindings>
<customBinding>
<binding name="MyCustomBinding">
<!-- available encodings: -->
<!-- <textMessageEncoding /> -->
<!-- <binaryMessageEncoding /> -->
<!-- <mtomMessageEncoding /> -->
<!-- <webMessageEncoding /> -->
<msmqTransport ...>
<msmqTransportSecurity ... />
</msmqTransport>
</binding>
</customBinding>
</bindings>
I guess I am restricted to one of the four pre-defined encodings: textMessageEncoding, binaryMessageEncoding, mtomMessageEncoding, webMessageEncoding.
On the client side I tried to alter the formatter:
System.Messaging.Message msmqMessage = new System.Messaging.Message();
msmqMessage.Formatter = new System.Messaging.ActiveXMessageFormatter();
//msmqMessage.Formatter = new System.Messaging.BinaryMessageFormatter();
//msmqMessage.Formatter = new System.Messaging.XMLMessageFormatter();
It seems that no formatter fits to an expected encoding.
Is there another way of unifying the encoding?
Perhaps a custom encoder or something like that?
Or am I completely wrong with adjusting formatter and encoder?
Thanks in advance.
You can use the built in MsmqIntegrationBinding and set the serialization format to xml:
<service name="MyQueueListenner">
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\myQueue"
binding="msmqIntegrationBinding"
bindingConfiguration="DotNetBinding"
contract="MyContract" />
</service>
...
<msmqIntegrationBinding>
<binding serializationFormat="Xml" name="DotNetBinding" durable="false" exactlyOnce="false">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
UPDATE
The whole point of integration binding is maximum interoperability so that wcf can support non-.Net msmq clients (ActiveX, Java).
For this reason exposing data contracts (beyond String) would not be meaningful.
I guess MS didn't really imagine people would use it for interop between lower .Net versions and WCF.
The only thing I can suggest is host a mex endpoint defining a set of one-way operations exposing your types over http and then allow clients to consume the wsdl from this endpoint.
They can then use this to build up their local type definitions for use with your msmq endpoint.
Just make it clear they should not actually call the http operations, or have the operations throw a NotImplementedException.

Using WCF on Localhost on Azure

In summary
How do I acces a WCF service on localhost when hosted in IIS on Azure? Azure does not bind localhost or 127.0.0.1 to my website.
Details
I have an ASP.Net application hosted on Azure. I have added a .svc and some workflows that I want to use via WCF. To keep matters simple, my web app simply calls the service on localhost, so I have endpoints like these in web.config;
<client>
<endpoint address="http://localhost:8080/Router.svc/Case" binding="basicHttpBinding" contract="NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow" name="Case" />
<endpoint address="http://localhost:8080/Workflow/Case/Case_default1.xamlx" binding="basicHttpBinding" contract="*" name="Case_default1" />
</client>
This works just fine on my local machine. The problem is that when I publish this to Azure, the Website in IIS does not get a binding to localhost, instead the bindings are always to the actual IP address of the server.
It ends up looking like this in applicationHost.config:
<bindings>
<binding protocol="http" bindingInformation="10.61.90.44:80:" />
<binding protocol="https" bindingInformation="10.61.90.44:443:" />
<binding protocol="http" bindingInformation="10.61.90.44:8081:" />
</bindings>
So, as soon as my web app tries to call the service on localhost (or 127.0.0.1 for that matter) it fails instantly.
Needless to say, if I rdp on to the server and change the binding then all is fine.
What I find really odd is that there are tons of examples out there where people are accessing WCF services on localhost on Azure so I can't figure out why this is so. I have set the osFamily to 2 and in order to debug this I have enabled web publishing and remote desktop access which I guess, in theory, could mess things up.
What I have already looked at
I can rewrite the end-point address in my code at runtime to substitute localhost for the actual address or create the endpoint dynamically as described by Ron in the answers. Unfortunately I am using the WCF Routing service so I can version workflows. This means that my code calls the Router endpoint and the WCF Router in turns calls the actual service/workflow using an endpoint specified in web.config. I don't have control over the Routing services endpoint resolution without, I think, writing a whole set of routing logic which just seems to be a lot of work when all I want is to call localhost :)
Switching to using named pipes; Alas, it causes some strange issues with workflows, probably due to duplexing, and I am on a deadline so haven't got time to get to the bottom of that at the minute.
You have to build the endpoint address dynamically.
Step 1:
In your ServiceDefinition.csdef you need to declare an Endpoint.
<ServiceDefinition name="MyFirstAzureWorkflow" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WorkflowWeb" vmsize="ExtraSmall">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="WorkflowService" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="WorkflowService" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
</WebRole>
</ServiceDefinition>
Step 2:
When you want to call the service
var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WorkflowService"].IPEndpoint;
var uri = new Uri(string.Format(
"http://{0}:{1}/MyService.xamlx",
endpoint.Address,
endpoint.Port));
var proxy = new ServiceClient(
new BasicHttpBinding(),
new EndpointAddress(uri));
Okay, so this is how I solved it. IMHO it's a hack but at least it works.
Basically, I need to add a "*" binding, so I can do this in Powershell. The general recipe is here: http://blogs.msdn.com/b/tomholl/archive/2011/06/28/hosting-services-with-was-and-iis-on-windows-azure.aspx
That deals with adding Named Pipes support, but the principle is the same. I just changed the Powershell script to:
import-module WebAdministration
# Set up a binding to 8080 for the services
Get-WebSite "*Web*" | Foreach-Object {
$site = $_;
$siteref = "IIS:/Sites/" + $site.Name;
New-ItemProperty $siteref -name bindings -value #{protocol="http";bindingInformation="*:8080:"}
}
This now allows me to use http://127.0.0.1:8080/service.svc to access my service.
Note: You do need to follow the rest of the recipe to set elevated execution context and change the powershell execution mode, so do follow it carefully

Content Type text/xml; charset=utf-8 was not supported by service

I have a problem with a WCF service.
I have a console application and I need to consume the service without using app.config, so I had to set the endpoint, etc. by code.
I do have a service reference to the svc, but I can't use the app.config.
Here's my code:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://localhost:8731/WcfServicio/MiServicio");
MiServicioClient svc = new MiServicioClient(binding, address);
object ob = svc.PaisesObtener();
At the last line when I do svc.PaisesObtener() I get the error:
Content Type text/xml; charset=utf-8 was not supported by service
http://localhost:8731/WcfServicio/MiServicio. The client and service bindings may be mismatched.
First Google hit says:
this is usually a mismatch in the client/server bindings, where the message version in the service uses SOAP 1.2 (which expects application/soap+xml) and the version in the client uses SOAP 1.1 (which sends text/xml). WSHttpBinding uses SOAP 1.2, BasicHttpBinding uses SOAP 1.1.
It usually seems to be a wsHttpBinding on one side and a basicHttpBinding on the other.
Do not forget check the bindings-related code too.
So if you wrote:
BasicHttpBinding binding = new BasicHttpBinding();
Be sure that all your app.config files contains
<endpoint address="..."
binding="basicHttpBinding" ...
not the
<endpoint address="..."
binding="wsHttpBinding" ...
or so.
I've seen this behavior today when the
<service name="A.B.C.D" behaviorConfiguration="returnFaults">
<endpoint contract="A.B.C.ID" binding="basicHttpBinding" address=""/>
</service>
was missing from the web.config. The service.svc file was there and got served. It took a while to realize that the problem was not in the binding configuration it self...
I saw this problem today when trying to create a WCF service proxy, both using VS2010 and svcutil.
Everything I'm doing is with basicHttpBinding (so no issue with wsHttpBinding).
For the first time in my recollection MSDN actually provided me with the solution, at the following link How to: Publish Metadata for a Service Using a Configuration File. The line I needed to change was inside the behavior element inside the MEX service behavior element inside my service app.config file. I changed it from
<serviceMetadata httpGetEnabled="true"/>
to
<serviceMetadata httpGetEnabled="true" policyVersion="Policy15"/>
and like magic the error went away and I was able to create the service proxy. Note that there is a corresponding MSDN entry for using code instead of a config file: How to: Publish Metadata for a Service Using Code.
(Of course, Policy15 - how could I possibly have overlooked that???)
One more "gotcha": my service needs to expose 3 different endpoints, each supporting a different contract. For each proxy that I needed to build, I had to comment out the other 2 endpoints, otherwise svcutil would complain that it could not resolve the base URL address.
I was facing the similar issue when using the Channel Factory. it was actually due to wrong Contract specified in the endpoint.
For anyone who lands here by searching:
content type 'application/json; charset=utf-8' was not the expected type 'text/xml; charset=utf-8
or some subset of that error:
A similar error was caused in my case by building and running a service without proper attributes. I got this error message when I tried to update the service reference in my client application. It was resolved when I correctly applied [DataContract] and [DataMember] attributes to my custom classes.
This would most likely be applicable if your service was set up and working and then it broke after you edited it.
I was also facing the same problem recently. after struggling a couple of hours,finally a solution came out by addition to
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
to your SVC markup file. e.g.
ServiceHost Language="C#" Debug="true" Service="QuiznetOnline.Web.UI.WebServices.LogService"
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
and now you can compile & run your application successfully.
Again, I stress that namespace, svc name and contract must be correctly specified in web.config file:
<service name="NAMESPACE.SvcFileName">
<endpoint contract="NAMESPACE.IContractName" />
</service>
Example:
<service name="MyNameSpace.FileService">
<endpoint contract="MyNameSpace.IFileService" />
</service>
(Unrelevant tags ommited in these samples)
In my case, I had to specify messageEncoding to Mtom in app.config of the client application like that:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="IntegrationServiceSoap" messageEncoding="Mtom"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:29495/IntegrationService.asmx"
binding="basicHttpBinding" bindingConfiguration="IntegrationServiceSoap"
contract="IntegrationService.IntegrationServiceSoap" name="IntegrationServiceSoap" />
</client>
</system.serviceModel>
</configuration>
Both my client and server use basicHttpBinding.
I hope this helps the others :)
I had this error and all the configurations mentioned above were correct however I was still getting "The client and service bindings may be mismatched" error.
What resolved my error, was matching the messageEncoding attribute values in the following node of service and client config files. They were different in mine, service was Text and client Mtom. Changing service to Mtom to match client's, resolved the issue.
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMySevice" ... messageEncoding="Mtom">
...
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
I had this problem in .net 6.0
The problem was the Soap Version, the BasicHttpBinding targets Soap 1.1 by default, but the service uses Soap 1.2.
The solution was to create a custom binding that targets Soap 1.2:
private Binding GetBindingConfiguration()
{
var textBindingElement = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
};
var httpsBindingElement = new HttpsTransportBindingElement()
{
MaxReceivedMessageSize = int.MaxValue,
RequireClientCertificate = true //my service require certificate
};
return new CustomBinding(textBindingElement, httpsBindingElement);
}
var binding = GetBindingConfiguration();
var address = new EndpointAddress("https://nfe.sefa.pr.gov.br/nfe/NFeAutorizacao4"); //Brazil NF-e endpoint that I had to consume.
var svc = new MyService(binding, address);
//my service requires certificate
svc.ClientCredentials.ClientCertificate.Certificate = certificado;
object ob = svc.PaisesObtener(); //call the method

Intermittent WCF error: Collection already contains an address with scheme http

I get this intermittent WCF error:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item
I tried various solutions by from googling around and from stackoverflow and they work for a while until the error shows up again and then I attempt another solution. It is really frustrating. Right now this is all voodoo to me as I don't understand why this is happening. It appears that if I touch the webconfig file and save it, the error disappears. I don't know if this causes it, but my webconfig is nested in that it lives under a special webservices folder. Any suggestions?
Take a look at how your IIS bindings are defined/configured in the IIS .config file located at...
C:\Windows\System32\inetsrv\config\applicationHost.config
Find your way to the Sites-Site-Bindings section, then look for bindings that have the same protocol defined. Example:
<binding protocol="http" bindingInformation="*:80:" />
<binding protocol="net.tcp" bindingInformation="8081:*" />
<binding protocol="net.pipe" bindingInformation="*" />
<binding protocol="net.msmq" bindingInformation="localhost" />
<binding protocol="msmq.formatname" bindingInformation="localhost" />
<binding protocol="https" bindingInformation="*:443:" />
<binding protocol="net.tcp" bindingInformation="9000:*" />
Notice there are two bindings for the "net.tcp" protocol. The above example configuration will throw the following error:
This collection already contains an address with scheme net.tcp. There can be at most one address per scheme in this collection. Paramter name: item
I personally experienced this error when I added the net.tcp protocol using the command prompt (as opposed to IIS Manager):
%windir%\system32\inetsrv\appcmd.exe set site "Default Web Site" -+bindings.[protocol-'net.tcp',bindinginformation-'9000:*']
If you have more than one http base endpoints (i.e. WsHttpBinding and BasicHttpBinding) and trying to add them at the same time, you will get this error.