I have created a WCF web service, i am calling it from ASP.NET 1.1 website.
I have added a simple operation contract to send a string value = IT WORKED.
Information on WCF Web service
I have added one DLL in the WCF web service.
I am accessing the DLL's exposed methods in the operation contract.
But i am facing an issue when i am invoking the operation contract :
In the web service i have referenced/added a DLL which is exposing some methods,
and i am calling those methods in my one operation contract.
description7a.Description7aPortType = this is coming from
the DLL i have added in the WCF service.
It is giving error :
Could not find default endpoint element that references contract
'description7a.Description7aPortType' 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.
How can i fix this?
WEB CONFIG OF WCF Web service
<system.serviceModel>
<services>
<service name="ADSChromeVINDecoder.Service" behaviorConfiguration="asmx">
<endpoint address="basic" binding="basicHttpBinding"
contract="ADSChromeVINDecoder.IService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="asmx">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 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>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Adding a service reference of the web service used by the DLL did the endpoint setting itself.
Related
We are currently implementing WCF services in Sitecore to execute certain tasks. However we want to secure and authenticate these interactions to keep the Sitecore security model intact.
We use following configuration for the authentication (only relevant config and anonymised):
<service name="Services.MailService" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="Interfaces.IMailService"/>
</service>
<behavior name="serviceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Services.Authentication.CustomServiceAuthentication, MyLibrary" />
</serviceCredentials>
</behavior>
<wsHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
<transport clientCredentialType="None">
</transport>
</security>
</binding>
</wsHttpBinding>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
The custom validator inherits from UserNamePasswordValidator and logs the user in using the standard Sitecore.Security.Authentication.AuthenticationManager.Login() method. On this exact moment the user is indeed logged in and appears as Sitecore.Context.User. But when arriving in the WCF method itself this authentication is gone. (resulting in access exceptions from Sitecore as anonymous user does not have add item rights)
After a few tests and studying the interactions I noticed that the issue would be that WCF uses multiple messages and thus multiple HttpContext are being used. The cookies and login are not being retained between the requests. Looking deeper I noticed that the System.ServiceModel.ServiceSecurityContext.Current does retain the security login however it only shows up once entering the WCF method (ea it's not possible to use this in the Sitecore httpBeginRequest pipeline to identify and login the user at the UserResolver)
How can I ensure both asp.net and wcf are properly authenticated throughout the call?
In the end we ended up resolving this by including the following in the constructor of the service since our InstanceContextMode was set to PerCall:
// Handle login for Sitecore to sync with the WCF security context
if (ServiceSecurityContext.Current != null)
{
AuthenticationManager.Login(
string.Format("{0}\\{1}", "yoursitecoredomain", ServiceSecurityContext.Current.PrimaryIdentity.Name));
}
We need to support both SOAP as well as REST interfaces into what is effectively the same function call. I understand SOAP is a protocol while REST is an architecture style, but I'm also sure web service developers know what I'm talking about; so lets not get distracted by the pedantic details. Also, I'd request avoiding a SOAP versus REST debate - we need both for business needs across different customers. The platform is ASP.NET 4.0.
REST:
I'm using WCF and essentially inputData is consumed by FunctionA to produce OutputData. I've got the abstract interface defined via the [ServiceContract] and the actual service logic exposed via the [WebInvoke] keyword. i.e.
[WebInvoke(UriTemplate = "funcA", Method = "POST", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
public OutputType FunctionA(InputType inputData)
SOAP
For the SOAP interface, I essentially need the same inputData going into the same FunctionA() which spits out the same OutputData (of type OutputType). Of course, these will be wrapped inside SOAP envelopes etc.
So my question is: How can I leverage the framework so that supporting a SOAP interface into the same functionality can be done with minimal custom code?
Find my service below that provides support for both SOAP and REST
[ServiceContract]
public interface ISampleService
{
[WebGet]
[OperationContract]
string GetData();
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SampleService : ISampleService
{
public string GetData()
{
return "Welcome to server";
}
}
My web.config would have the following
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="RestBinding">
<readerQuotas maxStringContentLength="5242880" maxArrayLength="16384"
maxBytesPerRead="4096" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="XMLService.SampleService">
<endpoint address="" behaviorConfiguration="web" binding="webHttpBinding"
bindingConfiguration="RestBinding" name="SampleService" contract="XMLService.ISampleService" />
<endpoint address="soap" binding="basicHttpBinding" contract="XMLService.ISampleService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Now the URL for your service would look like as follows:
REST --> http://localhost/SampleApp/SampleService.svc/GetData
SOAP --> http://localhost/SampleApp/SampleService.svc
If you want the REST url to be clean i.e. not have .svc in it then you can follow the WebAPI approach where you register your route in Global.asax and removed the endpoint from the config. You can perform tha same for your POST operation. Also make sure that if you are passing in complex types you need to let the service know if the types as shown below
[KnownType(typeof(SampleItem))]
The above attribute needs to be placed on the class implementing the interface.
One of the projects I'm working on has this exact functionality.
Our WCF service is multi tired
Data Access Layer
Business Logic Layer
Service Layer
The Service Layer has 2 End Points
SOAP
Rest
The End Points are very thin and basically consume methods from the BLL. So taking your example, Function A would be defined in the Business Logic Layer, where all the work would be done. Each of your Endpoints Would also have FunctionA which calls FunctionA from the BLL.
The Visual Studio Solution for this consists of a project for each of the BLL and DAL layers and a project for each of the end points. There are also a couple of other projects for unit tests etc
You have two good options:
Create a SOAP Service and a REST Service. The Endpoint of each calsl a shared class (so there is no code duplication, eg:
//SOAP endpoint
[webmethod]
public void DoSomething(int id)
{
myClass.MethodThatActuallyDoesTheWork(id);
}
//in another service we have the REST methods
//REST endpoint
public void DoSomething(int id)
{
myClass.MethodThatActuallyDoesTheWork(id);
}
OR (my prefered method)
Install the WCFWebAPI via Nuget (or whatever) as this allows content negotioation in that you write one method in your service. If THE CLIENT specifies Accept: application/xml then they get XML returned, if the client specifies Accept: application/json then they get JSON back.
I am not sure if this generates a WSDL though - if your using soap 'cos you want XML then this is a good method. If you need a WSDL then two services might be better.
Food for thought anyway. Hope this helps.
If you need to test a WSDL based XML service the WCFTestClient is pretty handy.
The WCFWebApi actually generates test/help pages for you too. It's great.
My service will be consumed by another application on the same box (Adobe AIR as it happens), and I can't run a server. I'm currently running a WCF service as a Windows service on the box to achieve this. No server means no REST (please do correct me if I'm wrong with any of this), but I still want my service to be able to return JSON.
I've been doing research on this, and finding lots of people using REST services with webHttpBinding and then setting a JSON behaviour in the config, however for reasons above I believe I can't use REST.
So with that as a background, my question is: Can a WCF service running as either basicHttpBinding, or WSHttpBinding (would like to avoid due to the overheads) return JSON without me having to hand roll it?
If so, would someone be good enough to explain how?
Here are the current details of my app.config for the service
<configuration>
<system.serviceModel>
<services>
<service name="WcfProjectLibrary.ProjectService">
<endpoint address="" binding="wsHttpBinding" contract="WcfProjectLibrary.IProjectService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfProjectLibrary/ProjectService/" />
</baseAddresses>
</host>
</service>
</services>
<!--<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>-->
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- 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="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Thanks
JSON can be returned only with webHttpBinding or custom binding using same binding elements as webHttpBinding and you can still host REST (with webHttpBinding) service in windows service. WebHttpBinding together with WebHttpBehavior are responsible for correct processing of non-SOAP messages.
I have no idea what you mean by no server. Process exposing the service is "a server" in terms of communication. You just need full .NET framework 4 (client profile is not enough) and http.sys installed (you will need it with any HTTP based binding).
I am running into a very strange issue here folks. For simplicity I created a project for the sole purpose of testing the issue outside the framework of a larger application and still encountered what is either a bug in WCF within Visual Studio 2010 or something related to my WCF newbie skill set : )
Here is the issue:
I have a WCF endpoint I created running inside of an MVC3 project called "SimpleMethod". The method runs inside of a .svc file on the root of the application and it returns a bool.
Using the "WCF Service Configuration Editor" I have added the endpoint to my Web.Config along with a called "LargeImageBinding".
Here is the service:
[OperationContract]
public bool SimpleMethod()
{
return true;
}
And the Web.Config generated by the Config Tool:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="LargeImageBinding" closeTimeout="00:10:00" />
</wsHttpBinding>
</bindings>
<services>
<service name="WCFEndpoints.ServiceTestOne">
<endpoint address="/ServiceTestOne.svc" binding="wsHttpBinding"
bindingConfiguration="LargeImageBinding" contract="WCFEndpoints.IServiceTestOne" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
The service renders fine and you can see the endpoint when you navigate to: http://localhost:57364/ServiceTestOne.svc - Now the issue occurs when I create a separate project to consume the service. I add a service reference to a running instance of the above project, point it to: http://localhost:57364/ServiceTestOne.svc
Here is the weird part. The service automatically generates just fine but In the Web.Config the endpoint that is generated looks like this:
<client>
<endpoint address="http://localhost:57364/ServiceTestOne.svc/ServiceTestOne.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceTestOne"
contract="ServiceTestOne.IServiceTestOne" name="WSHttpBinding_IServiceTestOne">
As you can see it lists the "ServiceTestOne.svc" portion of the address twice!
When I make a call to the the service I get the following error:
The remote server returned an error: (404) Not Found.
I tried removing the extra "/ServiceTestOne.svc" at the end of the endpoint address in the above config, and I get the same exact error.
Now what DOES work is if I go back to the WCF application and remove the custom endpoint and binding references in the Web.Config (everything in the "services" and "bindings" tags) then go back to the consumer application, update the reference to the service and make the call to SimpleMethod()....BOOM works like a charm and I get back a bool set to true.
The thing is, I need to make custom binding configurations in order to allow for access to the service outside of the defaults, and from what I can tell, any attempt to create custom bindings makes the endpoints seem to run fine, but fail when an actual method call is made.
Can anyone see any flaw in how I am putting this together? Thank you for your time - I have been running in circles with this for about a week!
When hosting a WCF service in IIS, the base address of the service is formed using the following format: {protocol}://{host}:{port}/{applicationName}/{svcFileName}. This is the address you can browse to get the WCF help page and/or the metadata (on a default configuration).
To form the actual address of the endpoint (the one your client needs to use), the following format is used: {serviceBaseAddress}/{endpointAddress}
Comparing the format above and the sample configuration you provided explains why you're getting ServiceTestOne.svc twice in your client address.
If you want the address of your service to be http://localhost:57364/ServiceTestOne.svc, I'd recommend leaving the address attribute empty in your endpoint configuration:
<endpoint address="" ... />
Background
I have created ASMX web services in the past and have been able to access the service from the web browser and Ajax GET requests using the address convention: MyService.asmx/MyMethod?Param=xxx
I just got started using WCF and created a new web service in my ASP.NET project. It creates a file with the .svc extension such as MyService.svc.
Current Situation
I am able to consume the service using the WcfTestClient that comes with VS2008. I am also able to create my own WCF Client by either adding a service reference in another project or using the svcutil.exe commandline to generate the proxy and config file.
The Problem
When I try to use the service from a browser using MyService.svc/MyMethod?MyParam=xxx, I get a blank page without any errors.
What I have tried
I have already added a basicHttpBinding to the web.config and made it HttpGetEnabled in the behavior configuration. I also added the [WebGet(UriTemplate = "MyMethod?MyParam={MyParam}")] attribute to my operation contract.
I have already followed the information in this other stack overflow question:
REST / SOAP EndPoints for a WCF Service
However, I either get a blank page or an HTTP 404 Error after following those steps. There's nothing special about the code. I am just taking in a string as a parameter and returning "Hello xxx". This is a basic "Hello WCF World" proof-of-concept type thing.
UPDATE - Here's the relevant code
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "MyMethod/MyParam={MyParam}")]
[OperationContract]
string MyMethod(string MyParam);
}
Web.Config - system.serviceModel Section
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address=""
binding="wsHttpBinding" contract="IMyService" />
<endpoint address="MyService.svc"
binding="basicHttpBinding" contract="IMyService" />
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Looking at your web.config serviceModel section, I can see that you need to add a webHttpBinding and associate an endPointBehavior that includes webHttpGet.
Your operation contract is correct. Here's how your system.serviceModel config section should look in order for you to be able to consume the service from a GET HTTP request.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address="ws" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="" behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Be sure to assign a different address to your wsHttpBinding endpoint, otherwise you will get an error saying that you have two endpoints listening on the same URI.
Another option is to leave the address blank in the wsHttpBinding, but assign a different address to the webHttpBinding service. However, that will change your GET address as well.
For example, if you assign the address as "asmx", you would call your service with the address "MyService.svc/asmx/MyMethod?MyParam=xxxx".
The normal WCF requests are always SOAP requests - you won't be able to get this going with just your browser, you'll need the WCF Testclient for that.
There is an add-on for WCF called the WCF REST Starter Kit (which will also be included in WCF 4.0 with .NET 4.0), which allows you to use GET/POST/PUT/DELETE HTTP commands to query WCF services and such. You need to write your services specifically for REST, though - you can't have SOAP and REST on the same service call.
Marc
As marc_s says, the REST Starter Kit can help, but you should also be aware that .NET 3.5 has support for REST services directly in it. It's not quite as complete as what you can do with the starter kit, but it is useful.
The way it works is that you put a [WebGet] attribute on your operations to indicate where in the URL the various parameters should come from:
[WebGet(UriTemplate = "helloworld/{name}")]
string Helloworld(string name);
See this portal for tons of information.
Note, you can have the same service exposed as both SOAP and REST if you specify multiple endpoints/bindings in the configuration.