Im trying to build a REST proxy as windows service. But every time my program executes a GET I receive "405 method not allowed"
Structure:
Code1 --GET--> Code2
Browser --GET--> Code1 --GET--> Code2
In the first case my code just makes a GET call to another REST server. Everything works fine.
In the second case I make a GET call from my browser to the first client and it will work as a proxy, redirecting the GET call to the second client. This doesnt work. POSTs are working, only the GET does not work.
I tried different URL paths and other URL structures.
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
namespace RUST_Console_Write
{
[ServiceContract]
public interface IService // <-- interface of second REST client
{
[OperationContract]
[WebGet(UriTemplate = "Test1/{s}")]
string Test1(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
[ServiceContract]
public interface IMITM_Service
{
[OperationContract]
[WebGet(UriTemplate = "GET1?s={s}")]
string EchoGet1(string s);
[OperationContract]
[WebInvoke]
string EchoWithPost(string s);
}
public class REST_CALLS
{
public static string makeGET(string s)
{
string messageResponse = "Response from other REST Service:\n";
try
{
using (ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(new WebHttpBinding(), "http://localhost:8001"))
{
channelFactory.Endpoint.EndpointBehaviors.Add(new WebHttpBehavior());
IService channel = channelFactory.CreateChannel();
Console.Write("Sending the GET... ");
messageResponse += channel.Test1(s);
Console.WriteLine("Success");
}
}
catch (Exception e)
{
Console.WriteLine("Failed");
Console.WriteLine(e);
}
return messageResponse;
}
public static string makePOST(string s)
{
string messageResponse = "Response from other REST Service:\n";
try
{
using (ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(new WebHttpBinding(), "http://localhost:8001"))
{
channelFactory.Endpoint.EndpointBehaviors.Add(new WebHttpBehavior());
IService channel = channelFactory.CreateChannel();
Console.Write("Sending the POST... ");
messageResponse += channel.EchoWithPost(s);
Console.WriteLine("Success");
}
}
catch (Exception e)
{
Console.WriteLine("Failed");
Console.WriteLine(e);
}
return messageResponse;
}
}
public class MITM_Service : IMITM_Service
{
public string EchoGet1(string s)
{
return REST_CALLS.makeGET(s); // <---- this one fails (405)
}
public string EchoWithPost(string s)
{
return REST_CALLS.makePOST(s); // <---- this one works fine
}
}
class Program
{
static void Main()
{
WebServiceHost host = new WebServiceHost(typeof(MITM_Service), new Uri("http://localhost:8000"));
ServiceEndpoint serviceEndpoint = host.AddServiceEndpoint(typeof(IMITM_Service), new WebHttpBinding(), string.Empty);
host.Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageEnabled = false;
host.Open();
Console.WriteLine("First call");
Console.WriteLine(REST_CALLS.makeGET("TEST")); // <---- this one works fine
Console.WriteLine("\nSecond call");
Console.WriteLine(REST_CALLS.makePOST("TEST")); // <---- this one works fine
Console.ReadLine();
host.Close();
}
}
}
Id really appreciate every help. Cant figure it out for my life.
(I know this isnt yet a windows service, the error is the same and its better to debug as normal program)
Related
I have class (named Sender) that has a member of Icommunicator interface which defines a WCF Service Contract.
public class Sender
{
private ICommunicator channel;
private ChannelFactory<ICommunicator> factory = null;
Inside the same .cs file there's a class Receiver which inherits from Icommunicator.
The interface that defines the service contract is as follow:
[ServiceContract(Namespace = "P2PComm")]
public interface ICommunicator
{
[OperationContract(IsOneWay = true)]
void PostMessage(CommMessage msg);
// used only locally so not exposed as a service method
CommMessage GetMessage();
[OperationContract]
bool openFileForWrite(string fileName);
[OperationContract]
bool writeFileBlock(byte[] block);
[OperationContract]
void closeFile();
}
Inside the Sender class there's a connect function which uses the Icommunicator channel member directly to call the PostMessage function.
// attempts to connect to Receiver instance
// attempts a finite number of times to connect to a Receiver
// first attempt to send will throw exception of no listener
// at the specified endpoint
// to test that we attempts to send a connect message
public bool connect(string toAddress)
{
int timeToSleep = 500;
CreateSendChannel(toAddress);
CommMessage connectMsg = new CommMessage(CommMessage.MessageType.connect);
connectMsg.to = toAddress;
connectMsg.from = fromAddress;
connectMsg.command = Msg.Command.connect;
while (true)
{
try
{
channel.PostMessage(connectMsg);
tryCount = 0;
lastUrl = toAddress;
return true;
}
catch (Exception ex)
{
if (++tryCount < maxCount)
{
Thread.Sleep(timeToSleep);
}
else
{
lastError = ex.Message;
lastUrl = "";
tryCount = 0;
return false;
}
}
}
}
I don't understand what is happening here I'm not inheriting from the Icommunicator interface but I'm using it to call one of its function, so which function gets called in this case ?
When I ran it with a debugger it did not step into a function, yet it was still able to send a message.
Please see this code:
namespace Server.Contracts
{
[ServiceContract]
public interface IMessageService
{
[OperationContract]
void DoWork(string message);
}
}
Server
namespace Server
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MessageService : IMessageService
{
public void DoWork(string message)
{
Console.WriteLine(message);
}
}
}
Client
namespace Client
{
class Program
{
static void Main(string[] args)
{
int i = 0;
var location = new[] { "London", "Paris", "New York", "Tokyo" };
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length <= 2)
{
// Start my Server...
Process.Start(#"C:\Server\bin\Debug\Server.exe");
}
i = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length;
string loc = location[i];
new Program().Stt(loc);
}
private void Stt(string loc)
{
Console.WriteLine("Press ank key to continue...");
Console.ReadLine();
var uri = "net.tcp://localhost:4565/MessageService";
var binding = new NetTcpBinding(SecurityMode.None);
var channel = new ChannelFactory<IMessageService>(binding);
var endpoint = new EndpointAddress(uri);
var proxy = channel.CreateChannel(endpoint);
if (proxy != null)
proxy.DoWork(loc);
Console.ReadLine();
}
}
}
So after i start my server and both the server and the clients running i want to send message:
if (proxy != null)
proxy.DoWork(loc);
So at this point i got this error although my server up and running:
System.ServiceModel.EndpointNotFoundException: 'There was no endpoint
listening at net.tcp://localhost:4565/MessageService that could accept
the message. This is often caused by an incorrect address or SOAP
action. See InnerException, if present, for more details.'
I am testing WCF for potentially implementing an API for remote controlling a device that runs our Controller-Software (C#/.Net 4.6.1) on Windows.
I am currently trying to figure out how to throw and catch a FaultException from my service and catch it from a .Net client.
The problem I am having is that when running the code (in Debug-mode on VS 2015), the exception is not caught by the client, but VS ends up showing me the exception inside VS at the code-location of the service (Service.cs), where it is being thrown. The exception message is:
An exception of type 'System.ServiceModel.FaultException`1' occurred in WcfService.dll but was not handled in user code
Additional information: The argument value was not 1
where The argument value was not 1 is the custom message provide by me. Here are the relevant parts of my code. I hope somebody can spot, what I am doing wrong:
IService.cs:
[ServiceContract(CallbackContract = typeof(IMyEvents))]
public interface IService
{
[OperationContract]
[FaultContract(typeof(InvalidValueFault))]
string ThrowsFaultIfArgumentValueIsNotOne(int value);
...
}
[DataContract]
public class InvalidValueFault
{
private string _message;
public InvalidValueFault(string message)
{
_message = message;
}
[DataMember]
public string Message { get { return _message; } set { _message = value; } }
}
Service.cs:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant,
InstanceContextMode = InstanceContextMode.Single)]
public class Service : IService
{
private string defaultString;
public Service(string ctorTestValue)
{
this.defaultString = ctorTestValue;
}
public string ThrowsFaultIfArgumentValueIsNotOne(int value)
{
if (value == 1)
return string.Format("Passed value was correct: {0}", value);
// this is where the box with the exception is shown inside Visual Studio
throw new FaultException<InvalidValueFault>(new InvalidValueFault("The argument value was not 1"), new FaultReason("The argument value was not 1"));
}
...
}
Server.cs:
public class Server
{
private ServiceHost svh;
private Service service;
public Server()
{
service = new Service("A fixed ctor test value that the service should return.");
svh = new ServiceHost(service);
}
public void Open(string ipAdress, string port)
{
svh.AddServiceEndpoint(
typeof(IService),
new NetTcpBinding(),
"net.tcp://"+ ipAdress + ":" + port);
svh.Open();
}
public void Close()
{
svh.Close();
}
}
Client.cs:
public class Client : IMyEvents
{
ChannelFactory<IService> scf;
IService s;
public void OpenConnection(string ipAddress, string port)
{
var binding = new NetTcpBinding();
scf = new DuplexChannelFactory<IService>(
new InstanceContext(this),
binding,
"net.tcp://" + ipAddress + ":" + port);
s = scf.CreateChannel();
}
public void CloseConnection()
{
scf.Close();
}
public string ThrowsFaultIfArgumentValueIsNotOne(int value)
{
try
{
return s.ThrowsFaultIfArgumentValueIsNotOne(value);
}
catch (System.ServiceModel.FaultException<InvalidValueFault> fault)
{
Console.WriteLine("Exception thrown by ThrowsFaultIfArgumentValueIsNotOne(2):");
Console.WriteLine("Exception message: " + fault.Message);
//throw;
return "Exception happend.";
}
}
...
}
Program.cs (Test Program using the server and the client):
class Program
{
static void Main(string[] args)
{
// start server
var server = new Server();
server.Open("localhost", "6700");
Console.WriteLine("Server started.");
var client = new Client();
client.OpenConnection("localhost", "6700");
Console.ReadLine();
Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(1): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(1));
Console.ReadLine();
Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(2): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(2));
Console.ReadLine();
client.CloseConnection();
Thread.Sleep(1000);
server.Close();
}
}
If you generated your SOAP code from wsdl using vs tools then FaultException that is being thrown here is generic FaultException - meaning it is FaultException<fault_contract>. You what generic type exception that is by checking your service reference code and inspecting [System.ServiceModel.FaultContractAttribute()] attribute. This attribute has Type parameter which is you generic type.
So if you it looks something like this
[System.ServiceModel.FaultContractAttribute(typeof(MyFaultContract)]
[System.ServiceModel.OperationContractAttribute(Action = "SoapAction", ReplyAction = "*")]
SoapResponse SoapAction(SoapRequest request);
then your catch clause should look like this
try {
soapClient.SoapAction(new SoapRequest());
}
catch (FaultException<MyFaultContract> e) {
}
I had his issue recently (if i understood correctly)
1) VS -> DEBUG -> Options and Settings -> Debugging -> General
There UNTICK 'Break when exceptions cross AppDomain...'
2) DEBUG -> Exceptions and deselect the exceptions for common language runtime (both Thrown and user-unhandled) and try it again. If that solves the problem, you can seek which exception(s) you want to customize or just do this whenever testing exceptions across the AppDomain.
Ok. I found the answer to my question by luck. The error was due to running my code in Debug mode in Visual Studio, where VS catches the exception the moment it is thrown. In order for it to work correctly you need to disable some settings. To do this go to Tools->Option->Debugging->General and remove the checkmarks:
Enable the exception assistant
Enable just my code
I found this solution here.
I am trying to pass a custom object from self hosted signalr hub server to all the clients, the method in client side not getting invoked .But if the same custom class object is passed from client to server works fine, meaning it invokes the server method.
below is the sample code :
public class ChatHub : Hub
{
public void Send(DataContract message)
{
//below call not reaching to client while passing custom obj
Clients.All.SendMessage(message);
//below string passing works - means invokes client method
Clients.All.SendMsg("test");
}
}
custom class defined in both client and server project via dll:
public class DataContract
{
public string Name
{
get;set;
}
public int Id
{
get;set;
}
}
client side method:
public class SignalRClient
{
HubConnection hubConnection = null;
IHubProxy chat;
public SignalRClient()
{
hubConnection = new HubConnection("https://localhost/");
chat = hubConnection.CreateHubProxy("ChatHub");
}
public void StartConnection()
{
if (hubConnection != null)
{
hubConnection.Start().Wait();
}
chat.On<DataContract>("SendMessage", (stock) =>
{
Console.WriteLine("name {0} id {1}", stock.Name, stock.Id.ToString());
});
chat.On<string>("SendMsg", (message) =>
{
Console.WriteLine(message);
});
}
public void SendMessage(DataContract dd)
{
dd.Name = "test";
chat.Invoke("Send", dd).Wait();
}
public void SendMessage(string msg)
{
chat.Invoke("SendMsg", "Console app", msg).Wait();
}
}
//program.cs
main()
{
SignalRClient client = new SignalRClient();
client.StartConnection();
string msg = null;
while ((msg = Console.ReadLine()) != null)
{
DataContract dd = new DataContract { Name = "arun", Id = 9 };
//below calls reaches to server both string type and custome obj
client.SendMessage(dd);
client.SendMessage("client");
}
}
Any clue on why when calling from server (i.e Clients.All.SendMessage(message); ) not invoking client method when param is custom object.
Thanks in advance.
I'm trying to POST to a REST service using the default WebHttpBinding binding. The service only accepts "text/xml" as the content-type and the WebHttpBinding is sending "application/xml, charset-utf=8". Is there a way to change the default content type without using the the HttpWebRequest?
You can use the WebOperationContext inside an operation scope to change the outgoing content type of the requests, as shown below.
public class StackOverflow_7771645
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string Process();
}
public class Service : ITest
{
public string Process()
{
return "Request content type: " + WebOperationContext.Current.IncomingRequest.ContentType;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
WebChannelFactory<ITest> factory = new WebChannelFactory<ITest>(new Uri(baseAddress));
ITest proxy = factory.CreateChannel();
using (new OperationContextScope((IContextChannel)proxy))
{
WebOperationContext.Current.OutgoingRequest.ContentType = "text/xml";
Console.WriteLine(proxy.Process());
}
using (new OperationContextScope((IContextChannel)proxy))
{
WebOperationContext.Current.OutgoingRequest.ContentType = "application/xml";
Console.WriteLine(proxy.Process());
}
((IClientChannel)proxy).Close();
factory.Close();
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}