I am getting an exception when trying to servialize the .NET ServiceController class. It serializes fine when it's null but once I populate it I get a stackoverflow exception.
So this works:
[DataMember]
public ServiceController MyServiceController
{
get { return null; }
}
But this gives the error "An unhandled exception of type 'System.StackOverflowException' occurred in System.ServiceProcess.dll":
public class TestClass
{
private ServiceController _serviceController;
[DataMember]
public ServiceController MyServiceController
{
get { return ServiceController.GetServices()[0];
}
}
A strange thing is that there is no error in the logs at all. When there is an error I can see it in the logs so it's not because my logs aren't working. Here is my config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyCompany.Wcf.RdbmsServer.RdbmsServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyCompany.Wcf.RdbmsServer.RdbmsServiceBehavior"
name="MyCompany.Wcf.RdbmsServer.RdbmsService">
<endpoint address="" binding="wsHttpBinding" contract="MyCompany.Wcf.RdbmsServer.IRdbmsService" bindingConfiguration="IncreaseMaxMessageSize">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/Design_Time_Addresses/MyCompany.Wcf.RdbmsServer/RdbmsService/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="IncreaseMaxMessageSize"
maxReceivedMessageSize="655360000">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="All"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "c:\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
Here is my service interface
[ServiceContract]
public interface IRdbmsService
{
[OperationContract]
TestClass GetServiceControllerList();
}
And the implementation is:
public TestClass GetServiceControllerList()
{
return new TestClass();
}
Any ideas?
You are causing the serializer to recurse:
public class TestClass
{
private ServiceController _serviceController;
[DataMember]
public ServiceController MyServiceController
{
get { return ServiceController.GetServices()[0]; // <-- this returns your service
}
}
The service this is returning is your IRdbmsService, which returns TestClass. This then needs to be serialized, etc.
Edit: To clarify:
When TestClass is serialized, the serializer looks at all of its DataMember properties, one of which is ServiceController. It then serializes this property, which does this on the get:
return ServiceController.GetServices()[0];
Since IRdbmsService is the only service defined in your scope, it is at index 0 from the response of the GetServices call, so it then must be serialized. Since the return type of GetServiceControllerList is TestClass, TestClass must then be serialized, which brings us back to the beginning (hence, the recursion).
As far as how to go about solving this, it depends on what you are trying to do. What this service is doing at the moment is returning information about itself to the caller, which doesn't make sense to me; the caller already has this information at the time of consumption (before making the call). Can you clarify your intent?
Yes, in the constructor of ServiceController CLASS, you are problably calling something recursive which don't have a condition to stop, so every time it calls something recursive, the program push to a stack, and as I said there is no stop condition, it will add to stack untill the memory explode, so it gives this error name StackOverFlow.
A suggestion: Add a break point to debug where its calling recursive. It's so easy when debugging.
Related
So I am trying to create a very basic WCF service with REST GET but there is only "Endpoint not found". I am sending GET via Postman App to address:
http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/json
Service is hosted by IIS; Here's all my code:
namespace RESTfulTest
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet]
string GetText();
}
}
namespace RESTfulTest
{
[ServiceBehavior(InstanceContextMode =InstanceContextMode.Single)]
public class Service1 : IService1
{
public string GetText()
{
return "Hello REST";
}
}
}
And App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="RESTfulTest.Service1">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/" />
</baseAddresses>
</host>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="RESTfulTest.IService1"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
What am I missing here?
Are you going to be using ASP.NET Ajax to call the service? If not, you should not be using the <enableWebScript> behavior, but rather the <webHttp> behavior.
Also, you should probably remove the <serviceMetadata> behavior, since you won't be exposing WSDL from your service.
So everything was set up properly. The endpoint address that I was asking was incorrect. It should be http://localhost:8733/Design_Time_Addresses/RESTfulTest/Service1/json/GetText
I didn't know that function name should be added to the address, that's the point.
I'm learning WCF, I started creating a very basic host app which defines a class with one method as follows:
[ServiceContract()]
public interface IMath
{
[OperationContract]
int Add(int a, int b);
}
public class MathCalcs : IMath
{
public MathCalcs()
{
Console.WriteLine("Service await two numbers...");
}
public int Add(int a, int b)
{
return a + b;
}
}
and that is how I configured the App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="ConsoleHost.MathCalcs" behaviorConfiguration="MathServiceMEXBehavior">
<endpoint address="http://localhost:8080/MathCalcs"
binding="basicHttpBinding"
contract="ConsoleHost.IMath"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/MathCalcs"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MathServiceMEXBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>
Then I called the service from Main
using (ServiceHost host = new ServiceHost(typeof(MathCalcs)))
{
host.Open();
Console.WriteLine("***The service is ready***");
}
Console.ReadLine();
But it fails to view the metadata of the service through the URI http://localhost:8080/MathCalcs, I'm sure I'm following the steps right as the book I'm reading from and as a preceding example works fine, the only difference is that I didn't separate the service logic (the interface and the class) in a stand alone class library.
What am I missing?
The following line of code
Console.ReadLine();
must be inside the braces of the using clause!
When that is done, retry finding the WSDL metadata.
Here is a related post that I think may lead you in the right direction.
WCF service showing blank in browser
I have a simple WCF service:
namespace Vert.Host.VertService
{
[ServiceContract]
public interface IRSVP
{
[OperationContract]
bool Attending();
[OperationContract]
bool NotAttending();
}
public class RSVPService : IRSVP
{
public RSVPService()
{
}
public bool Attending()
{
return true;
}
public bool NotAttending()
{
return true;
}
}
}
I'd like to self-host in a console application like so:
class Program
{
public static void Main()
{
// Create a ServiceHost
using (ServiceHost serviceHost = new ServiceHost(typeof(RSVPService)))
{
// Open the ServiceHost to create listeners
// and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
}
So I'm using this app.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
<system.serviceModel>
<services>
<service name="Vert.Host.VertService.RSVPService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Vert" />
</baseAddresses>
</host>
<endpoint
address="/RSVP"
binding="basicHttpBinding"
contract="Vert.Host.VertService.IRSVP" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
As I understand it, this setup would leave me with http://localhost:8080/Vert/RSVP/Attending as a valid REST URI to call from an arbitrary HTTPClient, but the call is hanging indefinitely or coming back with a 0 No Response (I'm using Advanced REST client)
What am I missing?
You are RIGHT in all of your setup...right up to the point where you stopped typing code and started telling me what you have. :)
What you've created is a std WCF service and you can get to it using a Service proxy or a ChannelFactory, but it will communicate with you as-is using SOAP.
You need this tutorial to turn this webservice into a RESTFUL service giving back Json/pox.
I have an application based around a WCF Duplex service. I have problems when the user "Restarts" the work the application does... under the hood, the client side closes the connection to the WCF service and creates another. The Service contract is defined like so...
[ServiceContract(Namespace="net.tcp://namespace.MyService",
SessionMode=SessionMode.Required,
CallbackContract=typeof(IServiceCallback))]
public interface IMyService
{
[OperationContract(IsOneWay=true)]
void DoWork();
}
public interface IServiceCallback
{
[OperationContract(IsOneWay=true)]
void SendMessage(string message);
}
The implementation is defined as:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single,
InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false,
IncludeExceptionDetailInFaults = true)]
public class MyService : IMyService
{
public void DoWork()
{
var callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
callback.SendMessage("Hello, world.");
}
}
The configuration for the client is as follows:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="net.tcp" receiveTimeout="02:00:00" sendTimeout="02:00:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8000/MyService/MyService"
binding="netTcpBinding" bindingConfiguration="net.tcp" contract="ExternalServiceReference.IMyService">
</endpoint>
</client>
</system.serviceModel>
Config for the service:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehaviour">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="netTcp" sendTimeout="01:00:00" receiveTimeout="01:00:00" >
<security mode="None">
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="serviceBehaviour" name="MyService.MyService">
<endpoint address="MyService" binding="netTcpBinding" bindingConfiguration="netTcp" name="net.tcp" contract="MyService.IMyService" />
<endpoint binding="mexTcpBinding" bindingConfiguration="" name="net.tcp" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8000/MyService" />
</baseAddresses>
</host>
</service>
</services>
In the client's contructor:
var callback = new CallbackImplementation();
_context = new InstanceContext(callback);
_proxy = new MyServiceProxy(_context);
I'm trying the following before I establish a new connection:
try
{
if (_context != null)
{
_context.ReleaseServiceInstance();
_context.Close();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
if (_context != null)
{
_context.Abort();
}
}
The issue I see is that the _context.Close() call always times out and throws an exception. Although I'm then aborting the channel, this feels wrong to me, and I believe it's the cause of freezing in my application. Does anybody know why the Close() call fails?
EDIT: I missed something earlier regarding my callback implementation that might be relevant. It looks something like this:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single,
UseSynchronizationContext = false,
IncludeExceptionDetailInFaults = true)]
public class CallbackImplementation : IServiceCallback
{
public void SendMessage(string message)
{
// Do something with the message
}
}
The exception message is "The ServiceHost close operation timed out after 00:00:30. This could be because a client failed to close a sessionful channel within the required time. The time allotted to this operation may have been a portion of a longer timeout.". There's no inner exception.
Thanks
I don't see an issue right off, but I often find that running traces on both the client and server and examining the results usually points me to the solution. Put this in your .config files (client and server), make sure the path points to a folder that exists. Run your app, get the failure, then shut everything down and run SvcTraceViewer.exe to read the results.
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information,ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\logs\TracingAndLogging-service.svclog" type="System.Diagnostics.XmlWriterTraceListener"
name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
have you tried receiveTimeout="infinite", to see if you still receive the error. You may just find that it's not the timeout creating the error. Have you thought about creating a base client class that automatically keeps the connections alive till physically closed?
At a guess, it could be a deadlock caused by the use of ConcurrencyMode.Single.
What could be happening is that the server is trying to call back to the client while it is still processing the original request (or vice versa). So server is trying to call back to client, but client is blocking because it is still waiting for a response from the server. Hey presto, deadlock and eventually a timeout.
http://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx
The issue was not only concurrency, but the binding type.
Making sure the concurrency mode of both the service and the callback was a step in the right direction. But changing the binding from netTcpBinding to wsDualHttpBinding has finally fixed the problem
I'm running a WCF service hosted in a WPF app, and am trying to raise an event in the host when a message is sent to the service, but am having great difficulty.
My code is as follows:
Service -
namespace BatService
{
[ServiceContract]
public interface IBatServ
{
[OperationContract]
void UseGadget(string name);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class BatServ : IBatServ
{
public void UseGadget(string name)
{
OnUsedGadget(name);
}
public static event EventHandler<BatArgs> UsedGadget;
public static void OnUsedGadget(string name)
{
if (UsedGadget != null)
UsedGadget(null, new BatArgs() { BatGadget = name });
}
}
public class BatArgs : EventArgs
{
public string BatGadget;
}
}
Host -
namespace BatHostWPF
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ServiceHost host = new ServiceHost(typeof(BatServ));
BatServ.UsedGadget += new EventHandler<BatArgs>(BatServ_UsedGadget);
host.Open();
}
void BatServ_UsedGadget(object sender, BatArgs e)
{
MessageBox.Show(e.BatGadget + " was used!");
}
}
}
Service 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="BatService.BatServ">
<endpoint address="" binding="wsHttpBinding" contract="BatService.IBatServ">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/BatService/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>
</configuration>
Host's App.config -
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NewBehavior0">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="NewBehavior0" name="BatService.BatServ">
<clear />
<endpoint address="net.pipe://localhost/battserv" binding="netNamedPipeBinding"
bindingConfiguration="" contract="BatService.IBatServ" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/batserv" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
As you can probably guess, I'm expecting to see a MessageBox when I call UseGadget() from a client. Whenever I try to test it out with VS's WcfTestClient.exe, nothing seems to happen at all. Where am I going wrong?
It turns out my endpoints weren't configured correctly. This page helped me solve my problems - http://www.switchonthecode.com/tutorials/wcf-tutorial-basic-interprocess-communication
I'm not sure if you can "raise events" in wcf, but you can create duplex communication architectures. The netTCPBinding, netNamedPipBinding and wsDualHttpBinding support this functionality.
Here is a video demonstration how to do callbacks with the wsDualHttpBinding
http://www.youtube.com/watch?v=NO2JsLrP75E
I've never done this with netNamedPipeBinding, but i assume the procedure is similar.
Remember to update your app.config files and service references when you're done with your implementation.
Hope that helps!