I've search a lot of already posted answers on stackoverflow, but none of the solutions proposed did not solve my problem so far. That's the second day of research & troubleshooting with no outcome, so I am to the point to ask for others help. I'm developing a WPF database application and I want to add a intermediate tier (WCF) between the WPF application and the database.
The WCF service has two service contracts, both with custom username/password authentication enabled (session is required as well). The first service contract (IAppUserService) will serve the WPF application which will be run by local users and the second service contract will serve a website accessible by customers (IAppClientService).
I've included the following source code:
DCMAppService.svc.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using System.IdentityModel.Selectors;
using MySql.Data.MySqlClient;
using DCMAppService.classes;
namespace DCMAppService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class AppClientService : IAppClientService
{
public bool Login(string userName, string password)
{
// TODO:
return true;
}
public bool Logout()
{
// TODO:
return true;
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class AppUserService : IAppUserService
{
private User currentUser;
#region User functions
public User Login(string userName, string password)
{
// Does Login here...
}
public bool Logout()
{
// Does logout here...
}
public bool isLoggedIn()
{
return (currentUser != null);
}
public User AddUser(string firstName, string lastName, string userName, string password, ushort status)
{
// Implements business logic...
}
public bool UpdateUser(uint id, string firstName, string lastName, string userName, string password, ushort status)
{
// Implements business logic...
}
public bool DeleteUser(uint id)
{
// Implements business logic...
}
public List<User> GetUsersList()
{
// Implements business logic...
}
#endregion
#region Client functions
public Client AddClient(string title, bool allowWebAccess, string userName, string password)
{
// Implements business logic...
}
public bool UpdateClient(uint id, string title, bool allowWebAccess, string userName, string password)
{
// Implements business logic...
}
public bool DeleteClient(uint id)
{
// Implements business logic...
}
public List<Client> GetClientsList()
{
// Implements business logic...
}
#endregion
}
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName == null || password == null)
throw new ArgumentNullException();
// Custom login implementation
// TODO:
int ret = 1;
if (ret != 1)
throw new FaultException("Invalid username or password", new FaultCode("AuthError"));
}
}
}
The service's Interface file contains the following:
IDCMAppService.cs
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace DCMAppService
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IAppClientService
{
[OperationContract(IsInitiating = true, IsTerminating = false)]
bool Login(string userName, string password);
[OperationContract(IsInitiating = false, IsTerminating = true)]
bool Logout();
}
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IAppUserService
{
[OperationContract]
bool HealthCheck();
#region User functions
[OperationContract(IsInitiating = true, IsTerminating = false)]
User Login(string userName, string password);
[OperationContract(IsInitiating = false, IsTerminating = true)]
bool Logout();
[OperationContract(IsInitiating = false)]
User AddUser(string firstName, string lastName, string userName, string password, ushort status);
[OperationContract(IsInitiating = false)]
bool UpdateUser(uint id, string firstName, string lastName, string userName, string password, ushort status);
[OperationContract(IsInitiating = false)]
bool DeleteUser(uint id);
[OperationContract(IsInitiating = false)]
List<User> GetUsersList();
#endregion
#region Client functions
[OperationContract(IsInitiating = false)]
Client AddClient(string title, bool allowWebAccess, string userName, string password);
[OperationContract(IsInitiating = false)]
bool UpdateClient(uint id, string title, bool allowWebAccess, string userName, string password);
[OperationContract(IsInitiating = false)]
bool DeleteClient(uint id);
[OperationContract(IsInitiating = false)]
List<Client> GetClientsList();
#endregion
}
}
Note that it contains two different service contracts that the WCF will have to serve (one for users and another one for clients).
The Web.config file contains the following:
<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>
<add name="DCMConnectionString" connectionString="Server=127.0.0.1;Database=xxxxxx;Uid=xxxxxx;Pwd=xxxxxx;" providerName="System.Data.EntityClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/>
</system.web>
<system.serviceModel>
<protocolMapping>
<remove scheme="http" />
<add scheme="http" binding="wsHttpBinding" />
</protocolMapping>
<bindings>
<wsHttpBinding>
<binding name="DCMAppBindingWSConfig" receiveTimeout="03:00:00"
sendTimeout="03:00:00">
<reliableSession inactivityTimeout="01:00:00" enabled="true" />
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
<mexHttpBinding>
<binding name="DCMAppBindingMexConfig" receiveTimeout="00:10:00"
sendTimeout="00:10:00" />
</mexHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="DCMAppService.AppServiceBehavior"
name="DCMAppService.AppUserService">
<endpoint address="" binding="wsHttpBinding" name="wsBinding"
contract="DCMAppService.IAppUserService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="DCMAppBindingMexConfig"
name="mexBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DCMAppService.AppServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="DCMAppService.CustomUserNameValidator, DCMAppService" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
What I get as a response is the error page with the classic message:
Metadata publishing for this service is currently disabled.
which is quite annoying as I cannot find any way to resolve it.
Any help would be very appreciated.