WCF Session Service hosted in ASP.NET MVC 2.0 application
I have a must to host WCF Service using WCF Session mechanism.
I've read http://msdn.microsoft.com/en-us/library/ms733040.aspx but it is not enough...
My simple scenearion:
I have solution with 4 projects.
First - SessionWCF.Base, it is simple Class Library that contains base interface IServiceBase for my service.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace SessionWCF.Base
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IServiceBase
{
[OperationContract(IsInitiating = true, IsTerminating = false)]
void BeginSession(string message);
[OperationContract(IsInitiating = false, IsTerminating = false)]
string GetMessage(int number);
[OperationContract(IsInitiating = false, IsTerminating = true)]
void EndSession();
}
}
Second - SessionWCF.Lib, it is WCF Class Library that contains service interface ISessionService and service class SessionService , it has project reference to SessionWCF.Base
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using SessionWCF.Base;
namespace SessionWCF.Lib
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ISessionService : IServiceBase
{
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace SessionWCF.Lib
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SessionService : ISessionService
{
string message = "";
#region ISessionService Members
public void BeginSession(string message)
{
this.message = message;
}
public string GetMessage(int number)
{
return "message: " + message + " number: " + number;
}
public void EndSession()
{
message = "";
}
#endregion
}
}
Third - SessionWCF.Web it is ASP.NET MVC 2.0 application that has inside SessionService.svc file. I've deleted code behind and opened XML editor, this service is pointed to service from SessionWCF.Lib, and of course this project has reference to SessionWCF.Lib.
SessionService.svc:
<%@ ServiceHost Language="C#" Debug="true" Service="SessionWCF.Lib.SessionService" CodeBehind="SessionWCF.Lib.SessionService.cs" %>
Web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="SessionServiceBehavior" name="SessionWCF.Web.SessionService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="largeMessageHttpBinding" contract="SessionWCF.Lib.ISessionService">
<identity>
<dns value="**********"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://**********/SessionWCF/SessionService.svc"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="largeMessageHttpBinding" maxReceivedMessageSize="10485760">
<readerQuotas maxArrayLength="100000"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="SessionServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Fourth - SessionWCF.WPF it is standard WPF application that contanins SessionProxy class and in xaml form click event to call web service. This project has project reference to first one SessionWCF.Base.
SessionProxy class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SessionWCF.Base;
using System.ServiceModel;
namespace SessionWCF.WPF
{
public class SessionProxy
{
public IServiceBase Proxy { get; set; }
public SessionProxy(string url)
{
WSHttpBinding binding = new WSHttpBinding();
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
binding.OpenTimeout = new TimeSpan(0, 1, 0);
ChannelFactory<IServiceBase> factory = new ChannelFactory<IServiceBase>(binding,
new EndpointAddress(url));
Proxy = factory.CreateChannel();
}
}
}
Click event in xaml form:
private void Button_Click(object sender, RoutedEventArgs e)
{
string url = "http://**********/SessionWCF/SessionService.svc";
SessionProxy client = new SessionProxy(url);
client.Proxy.BeginSession("my message");
string msg = client.Proxy.GetMessage(666);
client.Proxy.EndSession();
txtMsg.Text = msg;
}
Now:
When I call web service in web browser I've get following error:
Error in '/SessionWCF' Application.
Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[InvalidOperationException: Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.]
System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) +16376242
System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) +1940
System.ServiceModel.ServiceHostBase.InitializeRuntime() +82
System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) +64
System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) +789
System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +287
System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +1132
[ServiceActivationException: The serv开发者_Go百科ice '/SessionWCF/SessionService.svc' cannot be activated due to an exception during compilation. The exception message is: Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it..]
System.Runtime.AsyncResult.End(IAsyncResult result) +890624
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +180062
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +136
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1
When I call it in my xaml event I get ServiceActivationException:
The requested service, 'http://**********/SessionWCF/SessionService.svc' could not be activated. See the server's diagnostic trace logs for more information.
Is it wrong configuration in web.config? Maybe I'm missing something in service attributes? And the most important. Why it alerts me about BasicHttpBinding when I'm not using it ???
Any one could help me with this please? It is critical to my current project...
Regards, Daniel Skowroński
UPDATE:
@marc_s
Firstly:
I think that server-side is wrong because when I simply paste url 'http://**********/SessionWCF/SessionService.svc' in any web browser I'll get error "Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it. " instead metadata...
Secondly:
In my client WPF application I have always two options:
First - Create service reference and IDE will automatically generate proxy class and add all configuration to app.config.
Here I can't do that because I'm getting the same error as in web browser when I point to web service in Service Reference designer.
Second - Create poxy manually and app binding configuration from code, this gives me opportunity create proxy step by step, but it seems that ServiceActivationException it is the same problem "ACTIVATION", you can see in stack trace this lines:
[ServiceActivationException: The service '/SessionWCF/SessionService.svc' cannot be activated due to an exception during compilation. The exception message is: Contract requires Session, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it..]
System.Runtime.AsyncResult.End(IAsyncResult result) +890624
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.End(IAsyncResult result) +180062
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +136
Regards, Daniel Skowroński
UPDATE:
@marc_s
I don't this it is the case because:
Firstly:
<services>
<service name="SessionWCF.Web.SessionService"
behaviorConfiguration="SessionServiceBehavior">
Service name it is a name of web service file inside asp.net application, so it points to SessionService.svc which belongs to SessionWCF.Web assembly (the same name as project).
Secondly:
<%@ ServiceHost Language="C#" Debug="true"
Service="SessionWCF.Lib.SessionService"
CodeBehind="SessionWCF.Lib.SessionService.cs" %>
Service= is a factory method that gets "type" of the service to create, it also needs class description so CodeBehind= must be pointed to SessionService.cs file where factory method can find SessionService type inside SessionWCF.Lib assembly.
Mentioned two statements are not the issue because when NOT using State Service scenario this works like a charm...
I believe that for the State Service it must me configure something more in web.config are I'm missing something in interface/class description in WCF Class Library...
I'm still in critical situation...
Regards, Daniel Skowroński
UPDATE
@marc_s you wrote
I think you're wrong here on the SVC file - check out: msdn.microsoft.com/en-us/library/aa751792.aspx - the Service=".." attribute must be "The value of the Service attribute is the common language runtime (CLR) type name of the service implementation." - you need to specify the .NET name of the service implementation class here ! That's your SessionWCF.Lib.SessionService class.
I agree with you becouse it is exacly what I've wrote :-)
You point this article: http://msdn.microsoft.com/en-us/library/aa751792.aspx
But a few lines below and you will see what it is under the hood:
new ServiceHost( typeof( MyNamespace.MyServiceImplementationTypeName) );
So when I typed:
<%@ ServiceHost Language="C#" Debug="true"
Service="SessionWCF.Lib.SessionService"
CodeBehind="SessionWCF.Lib.SessionService.cs" %>
I pointed exacly: SessionWCF.Lib - namespace, SessionService - class where I have my service implemented.
I my example SessionWCF.Lib - it is both assembly name for .dll and namespace inside SessionWCF.Lib project what you can see at the top of this post when I describe second project in my solution, starting by "Second - SessionWCF.Lib, it is ..."
And again this solution WORKS perfectly without Session functionality of WCF, but it is NOT WORKING when I use WCF Session what I need...
Thanks for engagement but issue must be elsewhere...
UPDATE 2010-07-08
@marc_s was right about wrong configuration in web.config.
Proper configuration must have to be the same name as in Wcf Library:
<service behaviorConfiguration="SessionServiceBehavior" name="SessionWCF.Lib.SessionService">
Regards, Daniel Skowroński
@marc_s was right about wrong configuration in web.config.
Proper configuration must have to be the same name as in Wcf Library:
<service behaviorConfiguration="SessionServiceBehavior" name="SessionWCF.Lib.SessionService">
精彩评论