Meta data issue wcf rest - c#

So trying to create a rest service but I keep getting an error:
If I try to run it in a browser I get : The type 'WcfService2.Service1', provided as the Service attribute value in the ServiceHost directive could not be found.
namespace WcfService2
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public class HelloWorldService
{
[OperationContract]
[WebGet(UriTemplate = "")]
public string HelloWorld()
{
return "Hello world!";
}
}
}
namespace WcfService2
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
class Program
{
static void Main(string[] args)
{
WebHttpBinding binding = new WebHttpBinding();
WebServiceHost host =
new WebServiceHost(typeof(HelloWorldService));
host.AddServiceEndpoint(typeof(HelloWorldService),
binding,
"http://localhost:8000/Hello");
host.Open();
Console.WriteLine("Hello world service");
Console.WriteLine("Press <RETURN> to end service");
Console.ReadLine();
}
}
}

You're defining a REST-style WCF service using the WebHttpBinding.
The WCF Test Client is only usable for SOAP services - not for REST services. REST services can be tested using your regular browser, or tools like Fiddler.
The error message you're getting would almost indicate that you have a *.svc lying around somewhere, too, that gets in your way. Is that the case?

Related

Using the same dll in a web service and a client application

I'm updating a few web services that have some components in common, so I thought that by creating a library that has that code in it, it could ease maintenance. When using a class from said library, the web service forces me to call the method with its proxy class.
Since the system is somewhat old, I can't change the architecture. The compilation is made in x64. I've already attempted to change the "Reuse types in referenced assemblies".
Referencing a class "x" from the "y" library on a web service "w" forces me to use the class "w.x" instead of "y.x" on a service method call.
Best regards,
Fábio Jesus
The code that I can provide is the following:
Library
namespace Library1
{
public class Class1
{
}
}
Service
namespace Services
{
[ServiceContract]
public interface Service
{
[OperationContract]
void Method(Library1.Class1 cc);
}
}
Client
namespace Client
{
public class ClientControl : PageControl
{
public void Execute(){
using(var _service = new Services.Service){
var cc = new Library1.Class1();
_service.Method(cc);
}
}
}
}

TDD the WCF service class itself first

So I started to create TDD tests for a new WCF service I wanted to create. In TDD, you create the test, and start adding objects that don't exist yet into your tests. First object I wanted to test was that the service is not null after instantiated.
Then then I said wait, how the hell can you do that in WCF...a service extension is .svc. Yes there's a .svc.cs but the main parent is .svc. I don't see a way I can to TDD on this part where you've have something like this but it'd create an .svc instead of just a .cs:
[TestMethod]
public void UponInitialization_ServiceIsNotNull()
{
// Arrange
// Act
NyNewService service = new MyNewService();
// Assert
Assert.IsTrue(service != null);
}
This is a very fundamental necessary first test, testing the very simplest possible from the start...this is very common on any TDD or XP team doing TDD.
Any thoughts on how I can create a new .svc from within my test here? not a plain .cs?
I'd start with creating acceptance test for non-existing WCF service:
private Uri _baseAddress = new Uri("http://localhost:8713/service1");
private IService1 _client;
[SetUp]
public void Setup()
{
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress(_baseAddress);
var factory = new ChannelFactory<IService1>(binding, endpoint);
_client = factory.CreateChannel();
}
[TearDown]
public void TearDown()
{
if (_client != null)
((ICommunicationObject)_client).Close();
}
[Test]
public void ShouldReturnSampleData()
{
Assert.That(_client.GetData(42), Is.EqualTo("You entered: 42"));
}
Keep in mind, that nothing is created yet - we start from test. Now you can create service interface:
public interface IService1
{
string GetData(int value);
}
Test now compiles, but of course, it fails with error
Attempted to get contract type for IService1, but that type is not a
ServiceContract, nor does it inherit a ServiceContract.
Good, that's because we should mark our interface with [ServiceContract] attribute. We add this attribute and run test again:
Method GetData is not supported on this proxy, this can happen if the
method is not marked with OperationContractAttribute or if the
interface type is not marked with ServiceContractAttribute.
Ok, mark our service interface with required attributes:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Now we see another error (because nothing is actually running our non-existing service)
There was no endpoint listening at http://localhost:8713/service1 that
could accept the message. This is often caused by an incorrect address
or SOAP action. See InnerException, if present, for more details.
We can use ServiceHost to run our service (at this moment we need to create service class to compile tests):
private ServiceHost _host;
[SetUp]
public void Setup()
{
_host = new ServiceHost(typeof(Service1), _baseAddress);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
_host.Description.Behaviors.Add(smb);
_host.Open();
// creating client as above
}
[TearDown]
public void TearDown()
{
// closing client as above
if (_host != null)
_host.Close();
}
You also need to implement IService1 interface by service class (otherwise test will fail):
public class Service1 : IService1
{
public string GetData(int value)
{
throw new NotImplementedException();
}
}
Now I'd created some unit-tests for Service1 class in order to implement GetData functionality. With these tests passing you will have acceptance test passing also. Thats it. You did test first, and your WCF service is completely ready to be hosted.

Service endpoint not found?

Seem to run into a service endpoint not found problem when trying to get from my service.
if I try http://localhost:8000/hello/help I should expect to see <string>You entered help <string> but I only get the no endpoint instead? I havent touched my config files at all and I am just hosting from a console app.
Host:
namespace Host
{
class Program
{
static void Main(string[] args)
{
WebHttpBinding binding = new WebHttpBinding();
WebServiceHost host =
new WebServiceHost(typeof(Service1));
host.AddServiceEndpoint(typeof(IService1),
binding,
"http://localhost:8000/hello");
host.Open();
Console.WriteLine("Hello world service");
Console.WriteLine("Press <RETURN> to end service");
Console.ReadLine();
}
}
}
Service1:
namespace WcfServiceLibrary1
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
IService1:
[ServiceContract]
public interface IService1
{
[WebGet(UriTemplate = "/{value}")]
string GetData(string value);
Remove the / from {value} and make sure it is listed as an OperationContract. It should be:
[WebGet(UriTemplate = "{value}")]
[OperationContract]
The base URL will come through with the trailing slash, so you are really looking for http://localhost:8000/hello//help in the current code
A stab in the dark ... by default, arbitrary processes are not permitted to listen on network ports.
When IIS is installed, the account that runs IIS is given permission - if you want other applications run by other accounts (console applications, windows services) to be able to listen to a port, you need to grant the permission.
Check out the netsh add urlacl command as a starting point.

How to create a winform app in visual studio 2010 to host a wcf service

I have a working skeleton WCF service. I want to host it in a winform app with a simple start and stop button.
This is how I host in a console app, easy to change to win app
public Program()
{
Console.WriteLine("This is the SERVER console");
var myUri = new Uri[1];
myUri[0] = new Uri(ConfigurationManager.AppSettings["baseAddress"]);
var timeEntryService = new WCFTimeEntryService();
var host = new ServiceHost(timeEntryService, myUri);
host.Open();
Console.WriteLine("Service Started!");
Console.WriteLine("Click any key to close...");
Console.ReadKey();
host.Close();
}
EDIT
First you need an interface that both client and server will use to communicate.
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Data;
namespace TimeEntryService
{
[ServiceContract]
public interface ITimeEntry
{
[OperationContract]
string Ping();
}
}
Then you create the class that will do the work when a client calls.
using System.ServiceModel;
using System.Data;
namespace TimeEntryService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WCFTimeEntryService : ITimeEntry
{
public string Ping()
{
return "Pong";
}
}
}
Then make sure you update your App.config (Use WCF Service Configuration Editor)
In my VS2010 its under Tools -> Service Configuration Editor
(Not sure if you need to do something to get it to show there).
When it runs up, you can use the WCF Test Client to confirm its working.
C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe

WCF: Accessing the service instance from the server

Context:
I need to develop a monitoring server that monitors some of our applications (these applications are in c#). So I decided to develop the system with WCF which seems suitable for my needs.
These applications must register themselves to the monitoring server when they start. After that the monitoring server can call the methods Start or Stop of these applications.
Everything is completely executed on the same machine, nothing needs to be executed remotely.
So I developed a good prototype and everything works fine. Each application registers itself to the monitoring server.
Question:
ApplicationRegistrationService (see the code below) is the implementation of the monitoring service and it is a singleton instance due to the ServiceBehavior attribute.
Here my problem: I want to access the content of ApplicationRegistrationService per example, the number of connected applications from my server (ConsoleMonitoringServer in the example). But, I am not sure how to achieve this.
Do I need to create a channel in my server to the service like I did in my clients (ConsoleClient) or it exists a better way to achieve this?
Code:
The code is very simplified for the purpose of this question:
//The callback contract interface
public interface IApplicationAction
{
[OperationContract(IsOneWay = true)]
void Stop();
[OperationContract(IsOneWay = true)]
void Start();
}
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IApplicationAction))]
public interface IApplicationRegistration
{
[OperationContract]
void Register(Guid guid, string name);
[OperationContract]
void Unregister(Guid guid);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ApplicationRegistrationService : IApplicationRegistration
{
//IApplicationRegistration Implementation
}
public class ApplicationAction : IApplicationAction
{
//IApplicationAction Implementation
}
Console application for this example
class ConsoleClient
{
static void Main(string[] args)
{
ApplicationAction actions = new ApplicationAction();
DuplexChannelFactory<IApplicationRegistration> appRegPipeFactory =
new DuplexChannelFactory<IApplicationRegistration>(actions,
new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/AppReg"));
IApplicationRegistration proxy = appRegPipeFactory.CreateChannel();
proxy.Register(Guid.Empty, "ThisClientName");
//Do stuffs
}
}
Console server for this example
class ConsoleMonitoringServer
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(ApplicationRegistrationService),
new Uri[]{ new Uri("net.pipe://localhost")}))
{
host.AddServiceEndpoint(typeof(IApplicationRegistration),
new NetNamedPipeBinding(), "AppReg");
host.Open();
//Wait until some write something in the console
Console.ReadLine();
host.Close();
}
}
}
Finally, I find the answer and it was pretty easy. I just need to create the service instance and pass the reference to the constructor of ServiceHost.
So I need to replace the following code:
using (ServiceHost host = new ServiceHost(typeof(ApplicationRegistrationService),
new Uri[]{ new Uri("net.pipe://localhost")}))
by :
ApplicationRegistrationService myService = new ApplicationRegistrationService();
using (ServiceHost host = new ServiceHost(myService,
new Uri[]{ new Uri("net.pipe://localhost")}))
If you mean you'd like two way communication between your monitoring service and your registered services or nodes, then you probably should be using two way communication in WCF also known as duplex communication. Very cool stuff.
http://www.codeproject.com/KB/WCF/WCF_Duplex_UI_Threads.aspx

Categories