I recently made a WCF service in C# and hosted it on a server running IIS 8.
Everything worked perfectly when testing locally and I was able to test all of my methods with success. My issue comes when I try to add a service reference to that WCF service in a separate project, the only methods it exposes at this point are async methods even though I never implemented any of my methods as async.
An example of a method would be:
public string getName(User user)
{
return user.name;
}
Something as simple as that would work when I tested it in Visual Studio, but when I host it in IIS and try to add a service reference, the only method I can seem to call or have access to is:
getNameAsync
Why would it do this even though I never implemented it as async in the first place? On top of that, I cannot uncheck "generate methods for async" when I add the service reference in the first place.
Any ideas?
Edit: For reference, I am trying to test these methods inside of a Windows 8.1 app that references the service.
This is how the code is generated. Normally you will find also and event called GetNameCompleted for which you subscribed in the client code like that (after creating a the method ClientGetNameCompleted):
client.GetNameCompleted += ClientGetNameCompleted ;
In this method you will use the service result. something like that:
private void ClientGetNameCompleted (object sender, GetNameCompletedEventArgs e)
{
if (e.Result != null)
{
// use the e.Result that contains the returned data;
}
}
Related
I am trying to set up an R.net WCF service as a server to run R commands on.
I have set up a test WinForms application where everything works.
This is how I use it:
void init()
{
SetupPath()
engine = REngine.GetInstanceFromID("test");
if (engine == null) engine = REngine.CreateInstance("test");
engine.Initialize();
}
...
results.Add(engine.Evaluate(command).AsCharacter().ToArray());
I created an equivalent WCF service which should work exactly the same;
REngine.CreateInstance() returns a valid REngine object,
engine.Initialize() silently crashes my service. Try-Catch section is ignored so I cannot see what exactly is happening.
What is the correct way to use R.net within a WCF service?
What could be the reason of different behaviours?
Where can I see detailed logs of the crash?
Service calls which don't use R.net complete successfully.
Both winforms test application and WCF service are 64 bit (i need them to be). (I did not manage to set up a 64-bit IIS express application, so am using IIS instead).
I did not manage to find the reason of the problem, however, switching to R.NET.Community package did the trick.
I have a Windows Service that hosts a WCF service and I am successfully able to connect to it using WCFTestClient and a Custom Client. The windows service is based upon what used to be an exe, but since the program will be used for a long running process on a server, the service is a better route. The problem is that I cannot access static variables in the application from the WCF service.
In the .exe (I switched this to a .dll which is the server application) I use a global class implemented as such:
public static class Globals
{
....
}
This holds references to the major parts of the program so that if any part needs to reference another I can use the syntax Globals.JobManager.RunJob().
The problem that I am encountering is that the WCF service is not able to reference Globals at run-time. One example of where I need this to be done is in the GetJob method:
public class ConsoleConnection : IConsoleConnection
{
public string[] RetrieveJobList()
{
string[] jobs = Globals.JobManager.GetAllJobNames().ToArray();
return jobs;
}
}
This method returns null when tested in WCFTestClient and throws an exception in the created client.
I believe this issue to be caused by the way the Windows Service, WCF Service, and the application DLL are initiated. The current method is such:
public class ETLWindowsService : ServiceBase
{
....
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
Globals.InitializeGlobals();
serviceHost = new ServiceHost(typeof(ConsoleConnection));
serviceHost.Open();
}
....
}
Here the Windows Service starts, Calls the Globals.InitializeGlobals() that creates all the necessary parts of the application, then starts the WCF service (If this is the wrong way to do this, let me know. I'm piecing this together as I go). I'm assuming that these actions are being done in the wrong order and that is the cause of the problems.
Do I need to have the Windows Service create the WCF Service which in turn creates the application (this doesnt make sense to me), or do I have the Windows Service create the application which then creates the WCF Service? Or is there a third option that I am missing?
The application is in a .dll with the WCF in a separate .dll
I totally agree with Andy H.
If I review this kind of code, I won't try to make the stuff work with the global static variable (even if in the end this is probably possible). A static global class is smelly. First of all, I will figure out to make it work without it.
There are several solution: dependency injection, messaging communication, event driven...
To help you: a long running process in a web service is very common, youy have a good description
here. But in any case, it never uses a static class to synchronize the jobs :)
Improve your design, and you will see that your current problem won't exist at all.
I need to change my unit test from local to remote tests and so far I thought that all I had to do is change UrlToTest to point to another server... But VS keeps on insisting to create a Development Web Server instead of using the one that is already running.
So after reading some docs my question actually is do I have install Test Controller and Test Agent on both remote and local computer or what? What if the WebService is on Linux...
Note that I don't want to debug the application that I'm testing. I simply want tests to be executed for a WebService that is already running, that is deployed.
I probably should mention that all my tests consists of WebService calls and some checks like this:
[TestMethod()]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost("MainProjectName", "/")]
[UrlToTest("http://servername:port/websitename/TestingOnlyWebForm.aspx")]
public void LoginEmptyDataTest()
{
IUserService userService = CreateIUserService();
string email = "";
string password = "";
ReturnMessage<User> actual;
actual = userService.Login(email, password);
Assert.AreNotEqual(true, actual.Status);
Assert.AreNotEqual("db_error", actual.Info);
}
But I have also more complicated tests in which I change some data and send it to another WebService and so on.
Note that UrlToTest previously was pointing to localhost at which point it works but starts a developer server which is not what I want.
What you are trying to is not possible. All that generated unit test is trying to do is to run the test locally on the machine either using the development server by specifying AspNetDevelopmentServerHost or by using local IIS, when AspNetDevelopmentServerHost is not present.
If you want to test remote services right click your unit test project and add a service reference. Point to your service give it a namespace, say Services, and generate the proxies. Once you have the proxies generated just instantiate them and call the methods. Also remove all the unneeded attributes from your test. Your test should roughly look like this:
[TestMethod]
public void LoginEmptyDataTest()
{
using (var userServiceClient = new Services.UserServiceClient(
"BasicHttpBinding_IUserService",
"http://someremotehost/userservice.svc"))
{
var result = userServiceClient.Login("user", "password");
// asserts go here
}
}
This may solve your immediate problem however you should re-think what you are doing as #eglasius said. what happens if the code you call changes state internally? Next test might fail because of that so you need clean-up strategies otherwise your tests will be very brittle and you'll end up ignoring them.
Update: passing an address at run-time. Change the first parameter to whatever enpoint configuration name you have in your config file.
I'll take a stab in the dark at this one because I did something similar recently.
In my case my test project referenced the service project to provide visibility of the service and data contracts the Web Service implements and consumes.
To resolve this - though it can be ignored - move the contracts to a new project. Then have the service and test projects reference the new project, and remove the test projects' reference to the service.
Hope that makes sense!
Once the reference is removed, VS will no longer feel the need to start up your service when you run your tests.
You can disable the startup of the Service Host in the Project settings of your WCF Service Project. Right Click - WCF Options - Uncheck "Start WCF Service Host when debugging another project in the same solution".
You really have to consider the nature of what you're trying to achieve here.
It's hard to tell exactly what you're hitting of the code. I have the impression, you have is a website that calls a web service. You're testing the client code in that context, instead of just testing the service.
If that's the case, remove the attributes and point the url to the correct service like UrbaEsc guided you to. If you don't remove the attributes, you're running the calling code in the context of the site.
Even if the above is not the scenario, and based on what you replied to UrbanEsc in the comments, you'd then be testing an external call to the webservice initiated from the same site process.
You said:
"Found it, but VS still starts something on localhost and then trys to reach external server... Seems like VS is just not designed for real remote testing of webservices"
Read the above. I'd say you need to better understand what you're enabling. You can certainly test remote web services, like you can do pretty much anything you can code. You do that from client code that knows nothing different that what any other external client of the service would know. Support doesn't stop there, as you can do load testing of the service.
Note that what you're doing aren't unit tests, these are integration tests. Or depending on the scope of your system, full system tests.
i'd like to create a windows service that would be accessible via WCF from a web application.
The workflow would be:
Windows Service starts and would hold a default value in memory.
A web app would connect the windows service via wcf and take the value and after some processing set the value back in the memory.
In a while would happend the same as in point 2., and so on,so on
This value would be hold only in memory.
The point is I dont know where put the variable that would be hold in the memory of the windows service.There is a Service class wich is instancied in a Program class wich is static class. So whats the best place to put a variable that would be hold in the memory as long as the service is running ?
And second question,is it correct to reference the exe of the windows service in a DLL ??
There is a service class for every windows service that also contains the start and stop methods. However, for your service, I'd simply create a singleton class that is accessed from the class that handles the WCF client requests.
There's no need to reference the exe of the service (and I strongly recommend you not to do that), as when you're using WCF you'll insert a service reference into your client project and just need two methods to get and set the data.
I suggest: Design your operation and data contracts for the service and then create the service reference within your client project. That'll make things clear.
If you don't know what I'm talking about, I recommend googleing for WCF samples.
EDIT
You write in the comment that you created a service class with a private field. I suppose you didn't actually do what I suggested :-) I said: Create a singleton class that is accessed by the class that handles the get/set requests.
public class ValueHolder
{
private static ValueHolder m_singleton = null;
private int m_someValue;
private ValueHolder()
{
m_someValue = 0;
}
public static ValueHolder Instance
{
get
{
if (m_singleton = null)
m_singleton = new ValueHolder();
return m_singleton;
}
}
public int SomeValue
{
get { return m_someValue; }
set { m_someValue = value; }
}
}
So now you have a window service class that you use to host a WCF service. The WCF service contains methods to get/set the value from ValueHolder.Instance.SomeValue. These methods are exposed to the client using the data contract.
Start your service and add a service reference to the client using the respective option in Visual Studio (not a reference to the DLL, but a service reference!!). The client now accesses the get/set methods of the service.
Job done, where's my money? :-D
It almost sounds like a separate service might be a little overkill for what you're after - maybe you should take a look at Inter-Process shared memory.
Take a look at #3 in this article.
http://www.codeproject.com/KB/threads/csthreadmsg.aspx
I'm connecting to a web service hosted by a third-party provider. I've added a service reference in my project to the web service, VS has generated all the references and classes needed.
I'm connecting with this piece of code (client name and methods anonymized):
using (var client = new Client())
{
try
{
client.Open();
var response = client.Method(...);
return response.Status;
}
catch (SoapException ex)
{
throw CreateServiceException(ex);
}
finally
{
client.Close();
}
}
When reaching the client.Open(), I get an exception with this message:
The top XML element '_return' from
namespace '' references distinct types
System.Boolean and
Service.Status.
Use XML attributes to specify another
XML name or namespace for the element
or types.
In reference.cs, I can see that the "_return" variable is decorated with
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
Is there a problem with the wsdl, the generated service reference or in my code?
Update: Generating the service as an old school Web Service solves the problem. I've marked Sixto's answer as accepted for now, but I'm still curious what could've caused the problem and if any parameters to the service generator could solve the original problem.
If you were able to create a service reference then the WSDL is valid. The exception message is saying you have namespace/type ambiguity problem with _return. The generated code is probably using it in some context as a boolean and in another context as a Service.Status type.
I don’t call the ClientBase.Open method before invoking a service method because I’ve never seen the need for it. I do always call the Close & Abort methods as appropriate. The Open method basically just changes the state of the client to no longer be configurable. I’m not sure how that would trigger code in the generated class since it is an inherited method. I’d try just removing that line and see if you get the same exception. Otherwise, if you haven’t already done so, search the generated code for all the places _return is used and see if you can manually sort-out the appropriate type. You may need different names for each context.
Another way to troubleshoot the WSDL is to create a Web Reference (assuming it’s an HTTP based service) and see if the generate code works as expected. If it does work, go with the ASMX client unless you have a need for WCF proxy capabilities.