I have a WCF Windows Service that checks for MSMQ messages.
It picks the messages up ok but the ProcessMSMQMessage event does not seem to get called.
Any ideas why this is? Have I set ProcessMSMQMessage event correctly? Or am I missing something?
My code is below. Thanks.
WCF Service Class...
public partial class MyService : ServiceBase
{
private ServiceHost host;
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
string queueName = ConfigurationManager.AppSettings["ProcessMsgQueueName"];
if (!MessageQueue.Exists(queueName))
{
MessageQueue thisQueue = MessageQueue.Create(queueName, true);
thisQueue.SetPermissions("Everyone", MessageQueueAccessRights.ReceiveMessage);
}
try
{
Uri serviceUri = new Uri("msmq.formatname:DIRECT=OS:" + queueName);
// communicate to MSMQ how to transfer and deliver the messages
MsmqIntegrationBinding serviceBinding = new MsmqIntegrationBinding();
serviceBinding.Security.Transport.MsmqAuthenticationMode = MsmqAuthenticationMode.None;
serviceBinding.Security.Transport.MsmqProtectionLevel = System.Net.Security.ProtectionLevel.None;
serviceBinding.SerializationFormat = MsmqMessageSerializationFormat.Binary;
host = new ServiceHost(typeof(MyService.Service1)); // add watcher class name
host.AddServiceEndpoint(typeof(MyService.IService1), serviceBinding, serviceUri);
host.Open();
}
catch (Exception ex)
{
EventLog.WriteEntry("SERVICE" + ex.Message, EventLogEntryType.Error);
}
}
protected override void OnStop()
{
if (host != null)
host.Close();
}
}
IService1 Contract...
[ServiceContract(Namespace = "MyService")]
[ServiceKnownType(typeof(Events.Dashboard_Message))]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void ProcessMSMQMessage(MsmqMessage<Events.Dashboard_Message> msg);
}
Service1 Class...
public class Service1 : IService1
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void ProcessMSMQMessage(MsmqMessage<Events.Dashboard_Message> msg)
{
string msgName = msg.GetType().Name;
// send to eventlog
EventLog.WriteEntry("MyService", msgName);
}
}
Got it working finally.
The issue was in IService1 contract. Needed to add Action = "*".
[OperationContract(IsOneWay = true, Action = "*")]
Related
I have a self hosted WCF service for handling HTTP POST request.
My WCF service method will handle 2 types of request (1. getting data, 2. Do some action with given data).
My scenario :
1. Started Action request with large amount of data. : during the starting of that action do some processing.
2. client reads some results.
3. sending the remaining data for the previous action.
I implemented this using 'TcpListener' it is working.
Problem:
when i try to implement this scenario using WCF, i have got the 'Bad request' during the first action request.
[ServiceContract]
public interface ITest
{
[OperationContract, WebInvoke(Method = "POST", UriTemplate = "{*pathname}")]
Stream GetResponse(string pathname, Stream requestBody);
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Exact, ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false, IncludeExceptionDetailInFaults = true)]
class TestService : ITest
{
public Uri BaseUri { get; private set; }
public IPAddress Address { get; private set; }
public Int32 Port { get; private set; }
public bool IsStarted { get { return Host != null; } }
public ServiceHost Host { get; private set; }
public TestService()
{
}
public TestService(IPAddress ipAddress, int port)
{
if (ipAddress == null) { throw new ArgumentNullException("Address"); }
this.Address = ipAddress;
this.Port = port;
this.BaseUri = new Uri(string.Format("http://{0}:{1}", this.Address, this.Port));
}
public void Start()
{
if (IsStarted) { throw new InvalidOperationException("Service is already started."); }
Host = CreateServiceHost();
Host.Open();
}
public void Stop()
{
if (!IsStarted) { throw new InvalidOperationException("Service is already stopped."); }
Host.Close();
Host = null;
}
private ServiceHost CreateServiceHost()
{
ServiceHost host = new ServiceHost(typeof(TestService), this.BaseUri);
WebHttpBinding webhttpBinding = new WebHttpBinding();
webhttpBinding.MaxBufferPoolSize = int.MaxValue;
webhttpBinding.MaxBufferSize = int.MaxValue;
webhttpBinding.MaxReceivedMessageSize = int.MaxValue;
CustomBinding binding = new CustomBinding(webhttpBinding);
WebMessageEncodingBindingElement webEncoding = binding.Elements.Find<WebMessageEncodingBindingElement>();
webEncoding.ContentTypeMapper = new RawMapper();
host.AddServiceEndpoint(typeof(ITest), binding, new Uri(this.BaseUri.AbsoluteUri)).Behaviors.Add(new WebHttpBehavior());
return host;
}
public Stream GetResponse(string pathname, Stream requestBody)
{
Stream response=null;
/************** Process 'requestBody' **************/
//requestBody contains "MY_ACTION"
//{
// Find the start delimeter from response : START processing
// Find the end delimeter from response : STOP processing
//}
//requestBody contains "GET_MY_DATA"
//{
// Find data and send response
//}
return response;
}
}
public class RawMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
return WebContentFormat.Raw;
}
}
Any help/guidance would be great as I'm really stuck on this.
I have a test project that test the Inherit contracts and callback contract.
Update 1 : I updated all of the topic with interfaces implamantations
By reading this article: http://codeidol.com/csharp/wcf/Service-Contracts/Contract-Inheritance/#part-16
This is possibol but when i try it, it fails.
class Program
{
static void Main(string[] args)
{
ServiceHost Service_IServer = new ServiceHost(new ServiceImplemantation(), new Uri(#"net.tcp://localhost:8080/"));
Service_IServer.AddServiceEndpoint(typeof(IService), new NetTcpBinding(), "Service");
Service_IServer.Open();
ServiceHost Service_I_IP = new ServiceHost(new IPImplemantation(), new Uri(#"net.tcp://localhost:8080/"));
Service_I_IP.AddServiceEndpoint(typeof(I_IP), new NetTcpBinding(), "Service");
Service_I_IP.Open();
Console.ReadLine();
}
}
[ServiceContract]
public interface I_IP
{
[OperationContract]
string GetIP();
}
[ServiceContract]
public interface IService : I_IP
{
[OperationContract]
void ImTheServer_Print();
}
//
//
//
//
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class IPImplemantation : I_IP
{
public string GetIP()
{
return "1.2.3.4";
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ServiceImplemantation : IPImplemantation, IService
{
public void ImTheServer_Print()
{
Console.WriteLine("ImTheServer_Print");
}
}
The error:
The ChannelDispatcher at 'net.tcp://localhost:8080/Service' with contract(s) '"I_IP"' is unable to open its IChannelListener.
Ensure you decorate it as OneWay.
[OperationContract(IsOneWay = true)]
void GetIP();
I have the following types:
public enum MyEnum
{
Value1,
Value2
}
[DataContract]
public class Configuration
{
[DataMember]
public MyEnum MyValue { get; set; }
[DataMember]
public Credentials CredentialValues { get; set; }
}
[DataContract, KnownType(typeof(CustomCredentials))]
public class Credentials
{
}
[DataContract]
public class CustomCredentials : Credentials
{
[DataMember]
public string Property1 { get; set; }
[DataMember]
public string Property2 { get; set; }
}
And on my service interface, I have a function that returns an instance of Configuration with its CredentialValues property set to a fully populated instance of CustomCredentials. I receive no errors from the client or the server, but while the data is being property serialized on the server and received by the client, the properties on CustomCredentials never have a value. What do I need to change here in order to have these properties properly deserialized on the client?
For reference, the connection between client and server is made with a DuplexChannelFactory over a NetTcpBinding using a data/service contract project that is shared by the client and service applications (the service is self-hosted), so there are no service proxy types that could need to be regenerated.
Added this code to the Contracts project along with your DataContracts.
[ServiceContract(Namespace = "http://schemas.platinumray.com/duplex", SessionMode = SessionMode.Required, CallbackContract = typeof(IService1Callback))]
public interface IService1
{
[OperationContract(IsOneWay = true)]
void GetData();
}
public interface IService1Callback
{
[OperationContract(IsOneWay = true)]
void SetData(Configuration config);
}
Created the service.
public class Service1 : IService1
{
public void GetData()
{
var x = new Configuration()
{
MyValue = MyEnum.Value1,
CredentialValues = new CustomCredentials { Property1 = "Something", Property2 = "Something else" }
};
OperationContext.Current.GetCallbackChannel<IService1Callback>().SetData(x);
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost( typeof(Service1), new Uri[] { new Uri("net.tcp://localhost:6789") }))
{
host.AddServiceEndpoint(typeof(IService1), new NetTcpBinding(), "Service1");
host.Open();
Console.ReadLine();
host.Close();
}
}
}
Created the client.
public class CallbackHandler : IService1Callback
{
public void SetData(Configuration config)
{
Console.WriteLine(config.CredentialValues.GetType().Name);
Console.WriteLine(((CustomCredentials)config.CredentialValues).Property1);
Console.WriteLine(((CustomCredentials)config.CredentialValues).Property2);
}
}
class Program
{
static void Main(string[] args)
{
// Setup the client
var callbacks = new CallbackHandler();
var endpoint = new EndpointAddress(new Uri("net.tcp://localhost:6789/Service1"));
using (var factory = new DuplexChannelFactory<IService1>(callbacks, new NetTcpBinding(), endpoint))
{
var client = factory.CreateChannel();
client.GetData();
Console.ReadLine();
factory.Close();
}
}
}
Outputs the following as expected:
CustomCredentials
Something
Something else
So this actually worked without modifying any of your data contracts... The same results if I revert to a twoway operation and just return Configuration directly without using the callback.
Also tried making Credentials abstract but could not replicate your problem.
Have I missed something?
I want to send a data from WCF host (not service proxy) to the connected client with the service.
How can I achieve this?
You'll need to create a Duplex service. See this article for more information: http://msdn.microsoft.com/en-us/library/ms731064.aspx
Here's an example:
[ServiceContract(
SessionMode=SessionMode.Required,
CallbackContract=typeof(INotificationServiceCallback))]
public interface INotificationService
{
[OperationContract(IsOneWay = true)]
void Connect();
}
public interface INotificationServiceCallback
{
[OperationContract(IsOneWay = true)]
void SendNotification(string notification);
}
public class NotificationService : INotificationService
{
public static List<INotificationServiceCallback> Clients =
new List<INotificationServiceCallback>();
public void Connect()
{
Clients.Add(
OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>());
}
}
public class Notifier
{
void HandleReceivedNotification(string notification)
{
foreach (var client in NotificationService.Clients)
{
client.SendNotification(notification);
}
}
}
How can I obtain the domain name or full URL of the requester?
I'm not sure that I understand your question, but if you need the domain name of the Windows user making the call to a service operation, use this:
OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name
This will return "{domain}\{username}".
Try this and let me know what you think (you'll probably want to paste this code into an mstest project):
[TestClass]
public class AlternativeCredentials
{
// Contracts
[ServiceContract]
interface IMyContract
{
[OperationContract]
string GetUserName();
}
// Service
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
class MyService : IMyContract
{
public string GetUserName()
{
return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
}
// Client
class MyContractClient : ClientBase<IMyContract>, IMyContract
{
public MyContractClient() { }
public MyContractClient(Binding binding, string address) :
base(binding, new EndpointAddress(address)) { }
public string GetUserName()
{ return Channel.GetUserName(); }
}
#region Host
static string address = "net.tcp://localhost:8001/" + Guid.NewGuid().ToString();
static ServiceHost host;
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IMyContract), new NetTcpBinding(), address);
host.Open();
}
[ClassCleanup()]
public static void MyClassCleanup()
{
if (host.State == CommunicationState.Opened)
host.Close();
}
#endregion
[TestMethod]
public void UseUserNameCredentials()
{
using (MyContractClient proxy =
new MyContractClient(new NetTcpBinding(), address))
{
proxy.ClientCredentials.UserName.UserName = "MyUsername";
proxy.ClientCredentials.UserName.Password = "MyPassword";
proxy.Open();
Assert.AreEqual("EMS\\magood", proxy.GetUserName());
proxy.Close();
}
}
}