Edit System.Servicemodel values programmatically? - wcf

When using WCF, there is a section in the web.config as below.
<system.serviceModel>
<services>
<service name="abc">
<endpoint /> <---this
</service>
</services>
</system.serviceModel>
Is it possible to edit the area I've marked programmatically?
I can see there is a sytem.serviceModel namespace, but other than that I'm a bit lost.

If you want to change these parameters at runtime you can override ServiceHost.OnOpening()
E.g. to change port:
protected override void OnOpening()
{
foreach (ServiceEndpoint endpoint in Description.Endpoints)
{
string uriString = string.Format("{0}://{1}:{2}{3}",
endpoint.Address.Uri.Scheme,
endpoint.Address.Uri.Host,
endpoint.Address.Uri.Port + _basePort,
endpoint.Address.Uri.LocalPath);
endpoint.Address = new EndpointAddress(uriString);
}
base.OnOpening();
}

To complement Mike Mozhaev's answer, since your service is hosted in IIS you'll need a ServiceHostFactory to get a reference to the service host (or to use your own host). There's some information about it at http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/14/wcf-extensibility-servicehostfactory.aspx.

Related

How to debug CustomServiceHostFactory in WCF?

I've recently implemented a CustomServiceHostFactory and am wondering how to debug it by hitting breakpoints in code. Here is the factory:
public class CustomHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ServiceHost host = new ServiceHost(serviceType, baseAddresses);
//configure WsHttpBinding
ConfigureServiceThrottling(host);
return host;
}
private void ConfigureWshttpBinding(ServiceHost host)
{
//Do something here....
}
private void ConfigureServiceThrottling(ServiceHost host)
{
ServiceThrottlingBehavior throttle = host.Description.Behaviors.Find<ServiceThrottlingBehavior>();
if (throttle == null)
{
throttle = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 100,
MaxConcurrentSessions = 100,
MaxConcurrentInstances = 100
};
host.Description.Behaviors.Add(throttle);
}
}
}
I create this in an empty web project and here are the pertinent Web.config contents.
<service name="Company.Project.Business.Services.AccountService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address=""
binding="basicHttpBinding"
contract="Company.Project.Business.Contracts.Service.IAccountService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
<service name="Company.Project.Business.Services.AccountClassService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address=""
binding="basicHttpBinding"
contract="Company.Project.Business.Contracts.Service.IAccountClassService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<serviceHostingEnvironment>
<!-- where virtual .svc files are defined -->
<serviceActivations>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="AccountService.svc"
factory="Company.Project.WebHost.CustomHostFactory"/>
<add service="Company.Project.Business.Services.AccountClassService"
relativeAddress="AccountClassService.svc"
factory="Company.Project.WebHost.CustomHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
I publish this to IIS and can successfully browse to and consume the services. Here is a path to one for example.
http://company.server.local/Project/Account/AccountService.svc
I am now trying to programmatically apply WsHttpBinding with open/close/send timeouts, readerQuotas, etc. I am trying to do this all in code and it would be helpful if I could step into the CustomeHostFactory to debug but have no idea how to do that. Any help is much appreciated. Thanks.
Ok, I was totally confused here. Instead of trying to attach to the w3wp process, I just set the project with the CustomHostFactory as the startup project in Visual Studio. I put a breakpoint in the protected override ServiceHost CreateServiceHost method.
Then, when I run the project http://localhost:58326/ comes up in a browser. I then had to actually browse to an endpoint like so: http://localhost:58326/Account/AccountService.svc in order to hit the breakpoint.
Now I can debug my programmatic configuration of the service. Hopefully this helps someone else.

ServiceMetadataBehavior attribute not found WCF C++/CLI

I am referencing System::ServiceModel in my C++/CLI dll project (VS2012 Express). The following code fails with the following error and I can't find how to fix it.
error C2337: 'ServiceMetadataBehavior' : attribute not found
[System::ServiceModel::ServiceContractAttribute]
[System::ServiceModel::Description::ServiceMetadataBehavior]
public ref class PlaybackManager
{
public:
~PlaybackManager() { this->!PlaybackManager(); }
!PlaybackManager() { }
// Playback action methods
[System::ServiceModel::OperationContractAttribute]
void Play();
[System::ServiceModel::OperationContractAttribute]
void Stop();
[System::ServiceModel::OperationContractAttribute]
void Pause();
[System::ServiceModel::OperationContractAttribute]
void Previous();
[System::ServiceModel::OperationContractAttribute]
void Next();
[System::ServiceModel::OperationContractAttribute]
void Random();
};
EDIT1:
The caveat to this is that it is not possible to write a wcf service entirely with code, i.e without an app.config file. While the Service has the ServiceMetadataBehavior helper to create a metadata exchange behavior implementation, there is no such thing for the Endpoint. Is this "by design"?
How to: Publish Metadata for a Service Using Code
EDIT2:
OK, so the caveat above does not seem to be, necessarily, correct. Below is the app.config representing what I am trying to do in code and I get the same error if I remove the ServiceMetatdataBehavior attribute to the endpoint class implementation.
<configuration>
<system.serviceModel>
<services>
<service name="Engine.PlaybackManager">
<endpoint
address="net.tcp://localhost:7008/PlaybackManager"
binding="mexTcpBinding"
contract="IMetadataExchange"
/>
<endpoint
address="net.tcp://localhost:7008/PlaybackManager"
binding="netTcpBinding"
contract="Engine.PlaybackManager"
/>
</service>
</services>
</system.serviceModel>
</configuration>
The error is:
The contract name 'IMetadataExchange' could not be found in the list
of contracts implemented by the service PlaybackManager. Add a
ServiceMetadataBehavior to the configuration file or to the
ServiceHost directly to enable support for this contract.
The problem is, if I add the ServiceMetadataBehavior attribute to the PlaybackManager class I get the original error above, that it is not recognized. Any ideas?
I understand why nobody responded to this, "where do I begin" was the only possible response. So, in case someone falls on this with an equal amount of confusion that I had, here are some tips:
My main issue was with the mapping the xml config nomenclature (found in most examples online) with the code equivalents:
<services> maps to System::ServiceModel::ServiceHost
<behaviors> maps to "your instance of ServiceHost"->Description->Behaviors
<behavior> is type specific, the type being a nested element in the xml, thus:
<behavior> <serviceMetadata /> </behavior> maps to ServiceMetadataBehavior
<endpoint> maps to ServiceEndpoint
and finally:
the mex endpoint (the one with the ServiceMetadataBehavior added) needs it's own namespace, so add "/mex" to the end of your implementation endpoint uri address.
example:
implementation address = "net.tcp://localhost:5000/Engine"
mex address = "net.tcp://localhost:5000/Engine/mex"
Obviously these tips are not an explanation but I hope they might help someone as confused as I was when I asked the question.

connect programmatically to a WCF service through HTTPS

I am working on a project that uses WCF service. I have built the service, configured the web.config file, deployed it on a IIS 7 server. The service is accesed through HTTPS (on my dev machine, i have self-created the certificate).
Everything is fine when a create the ServiceReference in Visual Studio 2010, it creates the client and it works fine.
What i need is to create a client programatically (need a little flexibility), so when i try to connect "manually", it gives me a error like this:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
The code for web.config is: (i hope there is nothing wrong in it)
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="WcfService1.IService1" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
The procedure i wrote to access the WCF service is:
void proc()
{
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
WSHttpBinding bind= new WSHttpBinding();
EndpointAddress ea = new EndpointAddress(ADRESASSL);
var myChannelFactory = new ChannelFactory<IService1>(bind, ea);
IService1 client = null;
try
{
client = myChannelFactory.CreateChannel();
client.RunMethod1();
client.Close();
//((ICommunicationObject)client).Close();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
if (client != null)
client.Close();
}
}
The code for IService1
[ServiceContract]
public interface IService1 : IClientChannel
{
[OperationContract]
int RunMethod1();
//....................................
}
It seems i am doing something wrong here, the procedure raises the Exception i mentioned. Something more i must do to work, but i didn't figured it out.
Thanks in advance for any advice you can give me.
I haven't tested this, but I believe you need to set the security mode for the binding before you create the factory. The default mode for security for WSHttpBinding is SecurityMode.Message, and you want SecurityMode.Transport.
You can resolve this one of three ways, as follows.
First, you can use the overloaded version of the WSHttpBinding constructor to specify the security mode, like this:
WSHttpBinding bind= new WSHttpBinding(SecurityMode.Transport);
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Secondly, you can use the parameterless constructor and specify the security mode (and the client credential type) like this:
WSHttpBinding bind= new WSHttpBinding();
bind.Security.Mode = SecurityMode.Transport;
bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Third, you can place a binding configuration section in the client config and reference that section in the constructor, like this:
WSHttpBinding bind = new WSHttpBinding("TransportSecurity");
The third example assumes a wsHttpBinding section with the name "TransportSecurity" in the client config file.
For more information, check these MSDN articles:
How to: Set the Security Mode
WSHttpBinding Constructor
Well, solved the problem with the self created certificate.
I have changed the endpoint adress for both the programatically connection and the service reference in Viosual Studio 2010.
string ADRESASSL = "https://localhost/ServiciuSSLwsBind/Service1.svc";
now is
string ADRESASSL = "https://eu-pc/ServiciuSSLwsBind/Service1.svc";
I have changed the adress from localhost to the name of pc "eu-pc". It has to do with the domain the certificate was issued.
Using localhost or 127.0.0.1 worked only for one method or the other.
Hope this will help other guys who might run into this.

Not getting the expected results from WCF REST Service (Newbie)

I'm new to WCF Web Services. I'm trying to test my simple hello world web service.
For now, I'm doing self hosting. I'm at the point where I've started the host application, opened my browser and typed in the address to my resource. I've also run Fiddler and created a Request by using the Composer. In both cases, I get the "You have created a service." page that has a link to my .wsdl.
I was expecting to see the "Hello World" text in my Response or a web page that has "...Hello world".
What am I missing? or am I just misunderstanding the process?
App.Config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="My.Core.Services.GreetingService" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/greeting"/>
</baseAddresses>
</host>
<endpoint name="GreetingService" binding="webHttpBinding" contract="My.Core.Services.IGreetingService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
Host code
using System;
using System.ServiceModel;
using My.Core.Services;
namespace My.Service.Host
{
class Program
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(GreetingService)))
{
host.Open();
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
host.Close();
}
}
}
}
Hello World Contract and Service
using System.ServiceModel;
using System.ServiceModel.Web;
namespace My.Core.Services
{
[ServiceContract]
public interface IGreetingService
{
[OperationContract]
[WebGet(UriTemplate = "/")]
string GetGreeting();
}
}
using System.Collections.Generic;
namespace My.Core.Services
{
public class GreetingService : IGreetingService
{
public string GetGreeting()
{
return "Greeting...Hello World";
}
}
}
If I understand you correctly, you can see your wsdl link at the following url
http://localhost:8080/greeting
In order to now call your endpoint, you need to add it to the url like this
http://localhost:8080/greeting/GetGreeting/
I'm not entirely sure why you have the UriTemplate thing in there though other than my guessing that you probably just copy pasted it from an example. Unless you have specific query string parameters that you want defined, you don't really need it and it kind of tends to complicate things so I'd recommend taking it out. That means your Interface would look something like this...
[ServiceContract]
public interface IGreetingService
{
[OperationContract]
[WebGet]
string GetGreeting();
}
...and you can then lose the final "/" on the url.
I figure out the problem. When I use the url: "http://localhost:8080/greeting" the server sends the temp page. When I add the backslash "/" on the end of the url it execute my service.
so, "http://localhost:8080/greeting/" works and sends me the "...Hello World" back.

WCF, MVC2, obtaining access to auto generated WSDL and working through default endpoint not found issues

I’m trying to run a very basic web service on the same IIS7 website that runs a MVC2 application. This is presenting a couple of different issues, and I believe it has to do with my system.serviceModel, but obviously I don’t know for sure (or I would fix it).
On the server side I can run my service just fine, the help operation works like a charm. I can execute the default WCF operation GetData and supply a value through the FireFox address bar.
http://localhost/services/service1/getdata?value=3 (example)
The first problem I’m having is that when I navigate to the base service URI it will display the message below. While this isn’t the end of the world because I can still execute code by manipulating the address; I do expect something else to be displayed. I expect the standard new web service message explaining that by appending “?wsdl” to the address you will receive the auto generated WSDL. I cannot access my auto generated WSDL.
“Endpoint not found. Please see the
service help page for constructing
valid requests to the service.”
Problem number two is in regard to client applications connecting to my web service. I created a console application in separate Visual Studio solution and added a web service reference to Service1. In the Visual Studio tool I can see and use the two methods that exist in my service, but when I run the code I get the following exception.
InvalidOperationException Could not
find default endpoint element that
references contract
'ServiceReference1.IService1' 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.
Before I post my code (I’m sure readers are tired of reading about my struggles) I do want to mention that I’ve been able to run a WCF Service Library and Console application in the same solution flawlessly. There seems to be very few resources explaining WCF, WCF configuration, and working with MVC. I’ve read through several articles and either they were out-of-date or they were so simplistic they were nearly useless (e.g. click button receive web service named “Service1”).
To summarize; why am I not able to access the auto generated WSDL and how can I successfully connect my client and use the web service? Now the best part; the code.
Global.asax
//Services section
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
Web.Config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="DefaultEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
<mexEndpoint />
</standardEndpoints>
<services>
<service name="Project.Services.Service1" behaviorConfiguration="MetadataBehavior">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false" /> <!-- httpGetEnabled="true" does not solve the problem either -->
<!-- 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" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
IService1
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET")]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
Service1
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Client Program
class Program
{
static void Main(string[] args) {
Service1Client client = new Service1Client();
client.GetData(2);
}
}
Thanks for the help! The problem was inside of my Global.asax.cs.
Original:
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
New:
routes.Add(new ServiceRoute("services/service1", new ServiceHostFactory(), typeof(Service1)));
The difference was chaing the host factory from "WebServiceHostFactory" to "ServiceHostFactory".
The second part of my question regarding client connections is because configuration settings are not being generated. I have to manually type them for each client. Yikes!
To avoid manually typing client configuration I had to change my endpoint
Original
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
New
<endpoint binding="wsHttpBinding" contract="Project.Services.IService1" />
After making this change the service and client are working flawlessly.
A quick answer to one of your questions:
To summarize; why am I not able to
access the auto generated WSDL
<serviceMetadata httpGetEnabled="false" />
...needs to be
<serviceMetadata httpGetEnabled="true" />
...in order to be able to retrieve the WSDL over http. You have to tell WCF to generate service metadata, and you've told it not to.