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

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.

Related

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.

WCF 4 RESTful with HTTPS GET, POST or PUT

I'm desperately in need of a working example of a WCF 4 RESTful web service. Our SaaS ticketing system (zendesk.com) can communicate with an URL target using HTTP GET, POST or PUT. I have not done any web related work (only c# console apps) but have now been tasked to create a WCF 4 web service with the following requirements:
Secured via HTTPS
Secured via username / password
Read and process the data from the SaaS system that is transmitted as application/x-www-form-urlencoded information, for example:
http://somedomain/a/path?value=message+with+placeholders+evaluated
My current code is as follows:
namespace WcfService2
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke]
void ClearAlert(Stream input);
}
}
namespace WcfService2
{
public class Service1 : IService1
{
public void ClearAlert(Stream input)
{
StreamReader rawTicketData = new StreamReader(input);
string ticketData = rawTicketData.ReadToEnd();
rawTicketData.Dispose();
//Do some work with ticketData
}
}
}
The web.config file:
<services>
<service behaviorConfiguration="MetaDataBehavior" name="WcfService2.Service1">
<endpoint behaviorConfiguration="RestBehavior" binding="webHttpBinding" bindingConfiguration="" name="REST" contract="WcfService2.IService1" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="RestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<behaviors>
I am currently using only HTTP (not HTTPS) for development and testing hence the missing binding entry / entries for HTTPS as well as any entries for login purposes in the web.config, at least I assume that is what / where I need to add the needed configuration but again, I have no knowledge.
I would more than appreciate any help / assistance I can get in creating a web service with the three above described requirements.
Thanks to all!
William

WCF Service Can't find metadata when using class from external dll

I'm creating a WCF service that will be used to insert data into a database.
The WCF service runs normally when using functions that are scoped locally to within the interface and class of the service itself, however, it fails to start when I use a class that is in an external DLL.
I made sure that the class in the DLL has all the required attributes, but still can't run the service.
Any ideas?
EDIT:
This is the faulty function
public Dal_Users createProfile(DateTime dateOfBirth, string email, string firstname, bool genderIsMale, string lastname, string mphoneno, string nickname, string password, string pictureURL)
{
try
{
//generate new user object
/////////////////////////start user metadata/////////////////////////////////////////
Dal_Users newUser = new Dal_Users();
newUser.DateOfBirth = dateOfBirth;
newUser.Email = email;
newUser.FirstName = firstname;
newUser.GenderIsMale = genderIsMale;
newUser.LastName = lastname;
newUser.MPhoneNo = mphoneno;
newUser.NickName = nickname;
newUser.Password = password;
newUser.ProfilePicture = pictureURL;
//////////////////////////////end user metadata///////////////////////////////////////
//insert user in database, call updateUsers without an ID
newUser.UpdateUsers();
return newUser;
}
catch (Exception ex)
{
return new Dal_Users();
}
}
The class DAL_Users comes from a DLL and is marked as a DataContract
/// <summary>
/// this is the data access class for the table Users
/// </summary>
[DataContract]
public class Dal_Users
EDIT2:
My app.config looks like this
<system.serviceModel>
<services>
<service name="ProfileService.ProfileMgr">
<endpoint address="" binding="wsHttpBinding" contract="ProfileService.IProfileMgr">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<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>
The error I'm receiving is
Error: Cannot obtain Metadata from http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/mex If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error URI: http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/mex Metadata contains a reference that cannot be resolved: 'http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/mex'. Receivera:InternalServiceFaultThe server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.HTTP GET Error URI: http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/mex There was an error downloading 'http://localhost:8732/Design_Time_Addresses/ProfileService/Service1/mex'. The request failed with HTTP status 400: Bad Request.
Try setting includeExceptionDetailInFaults to true in your web.config so you can see the error message generated when requesting the MEX endpoint.
See this SO post which seems identical to the error you're receiving (HTTP status 400: Bad Request).
If you are trying to move your service and service contract to an external assembly, you need to modify your .svc file to point to that assembly.
<%# ServiceHost Language="C#" Debug="true" Service="FULLASSEMBLYNAMEHERE" %>

Two WCF services cannot interact when on same server

I have two WCF services hosted with a hosting provider. Both service to work fine. I can access them from my own computer or even from a website hosted with another provider. The weird part (at least, the part I don't understand) is; one cannot call the other.
Both services are located in a subfolder of the web root, at the same hierarchical level. Like wwwroot\serviceone and wwwroot\servicetwo. Both are marked as application folder in IIS en both have an almost similar web.config as shown below, only the names differ:
<configuration>
<system.web>
<compilation targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="servone">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="MyService.ServiceOne" behaviorConfiguration="servone">
<endpoint address="" binding="basicHttpBinding" contract=" MyService.IServiceOne "/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Browsing to the .svc displays the well-known service page with the example code;
class Test
{
static void Main()
{
ServiceOne client = new ServiceOne ();
// Use the 'client' variable to call operations on the service.
// Always close the client.
client.Close();
}
}
The client has a method named HandleRequest(string str). So in my code (C#) there's a line like;
client.HandleRequest("blah");
The call doesn't raise an exception (I can tell because they are catched, handled and written to a database). It's like the message is sent but never returns.
When I run this service (who calls the other) locally and leave the second on the remote server, all works well.
Obvious it is hard to provide all the details from the hosting party. Unfortunate I don't have access to an IIS installation to simulate the environment either. So, I'm not expecting an in-depth technical solution based on the little information I can provide. But any comment about how this setup differs from all others might be helpful.
I really appreciate any effort, thanks.
Edit:
The call is made like this:
public bool Send(String str)
{
bool result = false;
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress ep = new EndpointAddress("http://www.mydomain.com/ServiceTwo.svc");
client = new ServiceTwoClient(b, ep);
//
try
{
result = client.HandleRequest(str);
client.Close();
return result;
}
catch (Exception x)
{
Add2DbLog(x.Message);
return false;
}
}
The domain alias you're using may not work locally on the server. Log in to that server, launch a web browser, and navigate to the service URL used in your code (http://www.mydomain.com/ServiceTwo.svc). Ensure that you don't get any error messages.

WCF 4.0, can't invoke the service

In a solution, I added a "WCF Service Library". No problem with the default method. I added one :
In the interface :
[ServiceContract]
public interface ISecurityAccessService
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[OperationContract]
CompositeUser ListUser();
}
[DataContract]
public class CompositeUser
{
List<User> _listUser = new List<User>();
[DataMember]
public List<User> ListUser
{
get { return _listUser; }
set { _listUser = value; }
}
}
The interface implementation, the dataaccess iw working, I tested the DataService and no problem.
public class SecurityAccessService : ISecurityAccessService
{
public CompositeUser ListUser()
{
DataAccess.DataService service = new DataAccess.DataService();
CompositeUser compositeUser = new CompositeUser();
compositeUser.ListUser = service.ListUser();
return compositeUser;
}
}
When I execute and try to invoke, I receive this error message :
*An error occurred while receiving the HTTP response to http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary/ISecurityAccessService/. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.*
The App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="WcfServiceLibrary.SecurityAccessService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary/ISecurityAccessService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="wsHttpBinding" contract="WcfServiceLibrary.ISecurityAccessService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- 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>
<!-- 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>
Update 1
I made a working sample with database access. I just don't understand something in the "PersonService" class, why I have to make this loop. Solution is welcome.
Download 40ko .rar full example
your User class needs to be marked with the DataContract attribute and its methods with the DataMember attribute. It may also need to be marked as a KnownType in the CompositeUser class so that it is included in the types for the service. You can do that like so:
[DataContract]
[KnownType(typeof(User))]
public class CompositeUser
{
...
}
you'll be able to tell what the issue is from the logs. Either you'll get a 'cannot be serialized' message, in which case you need to add the [DataContract] attribute or it will be 'type was not expected' in which case you'll also need to add the [KnownType] attribute
If you enable tracing in your service you'll be able to get more details of what the problem was. Add something like this in the config file:
<configuration>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="System.ServiceModel" switchValue="Verbose">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="D:\wcfLog.svcLog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
also setting <serviceDebug includeExceptionDetailInFaults="True" />
will allow more detail about the error to be returned in the service exception which might also help.
EDIT
From the comments below it seems the User class is a Linq to SQL generated class. I don't think you should be sending this class across the wire. WCF deals with messages not in serializing types with behaviour, so you should create a DTO which represents the data in your User class that will be needed on the client and send this DTO out from the service contract. Even if you do send the User class as it is, when it gets to the client it won't have the context to still be connected to the DB.
I faced this problem again today. A long time ago I had the same problem, but I had forgotten the cause and it took me some time to sort it out toady.
In my case, it was a looping serialization problem. One table has a column which is a foreign key to another column in the same table. So all I had to do was to click the work surface of the dbml file and change the Serialization Mode to Unidirectional.
If yours is a Linq to Sql situation, and the error message is the one shown above, you might want to check whether it is the same cause as mine.