I am trying to setup NServiceBus Sagas using NHibernate persistence, but I think I have something configured incorrectly because I'm getting an error connecting to a service at 127.0.0.1:8080. I am able to get my saga to handle the command message, but after a few seconds the error message below appears in the console window and then the same command is fired again causing the handler in the saga to be invoked again. This happens repeatedly as long as I allow the application to run. I can tell NHibernate is connecting to my database because it creates a table for the saga data, however nothing is ever persisted in that table.
I think there is an error persisting the saga data, and my guess is that it may be trying to use the default RavenDb saga persistence but I'm not sure why this would be.
The error message I receive is the following:
WARN
NServiceBus.Unicast.Transport.Transactional.TransactionalTransport
[(null)] <(null)> - Failed raising 'transportmessage received' event
for message with ID=3753b476-7501-4fd8-90d0-b10aee95a578\22314
System.Net.WebException: Unable to connect to the remote server --->
System.Net.Sockets.SocketException: No connection could be made
because the target machine actively refused it 127.0.0.1:8080 at
System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot,
SocketAddress socketAddress) at
System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP) at
System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,
Socket s4, Socket s6, Socket& socket, IPAddress& address,
ConnectSocketState state, IAsyncResult asyncResult,Exception&
exception) --- End of inner exception stack trace --- at
NServiceBus.Unicast.UnicastBus.HandleTransportMessage(IBuilder
childBuilder, TransportMessage msg) at
NServiceBus.Unicast.UnicastBus.TransportMessageReceived(Object sender,
TransportMessageReceivedEventArgs e) at
System.EventHandler`1.Invoke(Object sender, TEventArgs e) at
NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.OnTransportMessageReceived(TransportMessage
msg)
A sample of the saga I am trying to use is (nothing fancy here, same thing happens whether or not I actually do something in the Handle method):
public class ItemSaga : Saga<ItemData>, IAmStartedByMessages<CreateItemCommand>
{
public void Handle(CreateItemCommand message)
{
}
}
public class ItemData : ISagaEntity
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }
}
My endpoint configuration looks like this:
public class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher, IWantCustomInitialization
{
public void Init()
{
var container = new UnityContainer();
container.AddNewExtension<Domain.UnityExtension>();
Configure.With()
.UnityBuilder(container)
.JsonSerializer()
.Log4Net()
.MsmqSubscriptionStorage()
.MsmqTransport()
.PurgeOnStartup(true)
.UnicastBus()
.ImpersonateSender(false)
.DisableTimeoutManager()
.NHibernateSagaPersister()
.CreateBus()
.Start(() => Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
}
}
And my app.config looks like this:
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
<MsmqTransportConfig NumberOfWorkerThreads="1" MaxRetries="5"/>
<NHibernateSagaPersisterConfig UpdateSchema="true">
<NHibernateProperties>
<add Key="connection.provider" Value="NHibernate.Connection.DriverConnectionProvider"/>
<add Key="connection.driver_class" Value="NHibernate.Driver.Sql2008ClientDriver"/>
<add Key="connection.connection_string" Value="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"/>
<add Key="dialect" Value="NHibernate.Dialect.MsSql2012Dialect"/>
</NHibernateProperties>
</NHibernateSagaPersisterConfig>
<connectionStrings>
<add name="EventStore" connectionString="Data Source=(localdb)\v11.0;Integrated Security=True;AttachDbFileName=|DataDirectory|\App_Data\EventStore.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NHibernate" publicKeyToken="aa95f207798dfdb4" />
<bindingRedirect oldVersion="0.0.0.0-3.3.0.4000" newVersion="3.3.1.4000" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Just a couple of notes:
This is from a sample app that I am using to test this functionality. It uses a local database file attached to localdb, however my full application using SQL Server 2012 is exhibiting the same behavior. I also had to add a dependenteAssembly entry for NHibernate because the NServiceBus.NHibernate NuGet package currently binds to an older assembly version (as of this posting).
As you can see, I am also using Unity as my IOC, but I have replicated this with a project using Ninject as well. I am using EventStore for my domain storage which is working great. I have command handlers that handle the command and publish events through EventStore to be handled by other processes. However, I have tried disabling all of those leaving me with just my Saga as a command handler and I still get the same error.
Does anyone have any ideas of what I may be doing wrong?
I have found a workaround to my problem. It seems to be an issue with using the built-in NServiceBus profiles. I was not specifying a profile in the command line arguments of the host, so by default it was loading the NServiceBus.Production profile. The Production profile, by default, uses RavenDB for all persistence.
Looking at the NServiceBus source on GitHub, the Production Profile Handler contains the following in the ProfileActivated method:
Configure.Instance.RavenPersistence();
if (!Configure.Instance.Configurer.HasComponent<ISagaPersister>())
Configure.Instance.RavenSagaPersister();
if (!Configure.Instance.Configurer.HasComponent<IManageMessageFailures>())
Configure.Instance.MessageForwardingInCaseOfFault();
if (Config is AsA_Publisher && !Configure.Instance.Configurer.HasComponent<ISubscriptionStorage>())
Configure.Instance.RavenSubscriptionStorage();
A couple of things to note here:
The profile will always call RavenPersistence() on the
Configure instance. I have not dug into the inner workings of that
method to see if it will actually bypass configuring Raven if other
persistence is already defined, but it will always run this method.
When I attach to the NServiceBus source and debug through
this code, in the second line HasComponent returns
false causing the RavenSagaPersister configuration to be run. This
happens even if I have NHibernateSagaPerister is defined in the endpoint
configuration.
I'm not sure if this behavior is by design, a bug, or misconfiguration on my part. However my workaround was to create my own profile. I had to move the NHibernate configuration calls from my endpoint config to my new profile, but once I did that I was able to use NHibernate persistence without errors.
My custom profile looks like the following (I borrowed the logging handler from the Production profile's logging handler):
public class MyProfile : IProfile
{
}
internal class MyProfileProfileHandler : IHandleProfile<MyProfile>, IWantTheEndpointConfig
{
void IHandleProfile.ProfileActivated()
{
Configure.Instance.NHibernateUnitOfWork();
Configure.Instance.NHibernateSagaPersister();
Configure.Instance.DBSubcriptionStorage();
Configure.Instance.UseNHibernateTimeoutPersister();
}
public IConfigureThisEndpoint Config { get; set; }
}
public class MyProfileLoggingHandler : IConfigureLoggingForProfile<MyProfile>
{
void IConfigureLogging.Configure(IConfigureThisEndpoint specifier)
{
SetLoggingLibrary.Log4Net<RollingFileAppender>(null,
a =>
{
a.CountDirection = 1;
a.DatePattern = "yyyy-MM-dd";
a.RollingStyle = RollingFileAppender.RollingMode.Composite;
a.MaxFileSize = 1024 * 1024;
a.MaxSizeRollBackups = 10;
a.LockingModel = new FileAppender.MinimalLock();
a.StaticLogFileName = true;
a.File = "logfile";
a.AppendToFile = true;
});
if (GetStdHandle(STD_OUTPUT_HANDLE) == IntPtr.Zero)
return;
SetLoggingLibrary.Log4Net<ColoredConsoleAppender>(null,
a =>
{
LiteLoggingHandler.PrepareColors(a);
a.Threshold = Level.Info;
}
);
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
const int STD_OUTPUT_HANDLE = -11;
}
A final note, I also had to set all of the properties of my saga data object as virtual, per standard NHibernate practice. This became very apparent once the system was actually using NHibernate.
public class ItemData : ISagaEntity
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
}
This is a long explanation, but hopefully it'll help someone else out down the road. If anyone has suggestions on a better way to accomplish this, or the correct way to use profiles, please let me know!
Related
I ran into a strange issue with publishing events to MSMQ using NServiceBus. I can successfully send messages using IBus.Send method (I can find the sent messages in MSMQ). However, when I try to publish an event using IBus.Publish method, the messages do not reach MSMQ. For each published message I only get the following log message.
[DEBUG] 2015-11-20 13:19:43.9444 Message type: 'MyAssembly.Messages.NewEmailEvent' could not be determined by a 'Type.GetType', scanning known messages for a match
The event definition looks like this.
namespace MyAssembly.Messages
{
public class NewEmailEvent
{
public Guid MessageId { get; set; }
public string Subject { get; set; }
public string Sender { get; set; }
// a few other fields
}
}
I am publishing the event using the following code.
m_Bus.Publish<NewEmailEvent>(msg => {
msg.MessageId = entry.MessageId;
msg.Subject = entry.Email.Subject;
msg.Sender = entry.Email.Sender.Name;
// more property assignments
});
I have the following routing configuration.
<MsmqTransportConfig InputQueue="Nsb_input" ErrorQueue="Nsb_errors" NumberOfWorkerThreads="1" MaxRetries="5" />
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
<UnicastBusConfig>
<MessageEndpointMappings>
<add Assembly="MyAssembly.Messages" Endpoint="NServiceBus.Service" />
</MessageEndpointMappings>
</UnicastBusConfig>
The event naming conventions are defined in code as follows.
busConfiguration.Conventions().DefiningEventsAs(
t => t.Assembly.GetName().Name.EndsWith(".Messages", StringComparison.InvariantCulture)
&& t.Name.EndsWith("Event", StringComparison.InvariantCulture));
The messages are correctly registered at startup.
[DEBUG] 2015-11-20 13:18:35.1345 Message definitions:
MessageType: MyAssembly.Messages.NewEmailEvent, Recoverable: True, TimeToBeReceived: Not set , Parent types: MyAssembly.Messages.NewEmailEvent
MessageType: NServiceBus.Scheduling.Messages.ScheduledTask, Recoverable: True, TimeToBeReceived: Not set , Parent types: NServiceBus.Scheduling.Messages.ScheduledTask
On the receiving end, I am subscribing to the event using the following code.
bus.Subscribe<NewEmailEvent>();
And using the following configuration.
<UnicastBusConfig>
<MessageEndpointMappings>
<add Assembly="MyAssembly.Messages" Endpoint="NServiceBus.Service" />
</MessageEndpointMappings>
</UnicastBusConfig>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
The event naming conventions are the same as the service.
Your MessageEndpointMappings are the same for both publisher and subscriber - don't know if this is correct / makes a difference.
You have not defined any message or command conventions; only events.
busConfiguration.Conventions()
.DefiningMessagesAs(t => t.Namespace != null &&
t.Namespace.StartsWith("MyAssembly.Messages"))
.DefiningCommandsAs(t => t.Namespace != null &&
t.Namespace.StartsWith("MyAssembly.Commands"))
I think you need to do this if you're not using marker interfaces.
I think this is especially important within the subscriber.
You haven't included the code for your subscriber. Does it have a class that implements IHandleMessages<NewEmailEvent>?
Go back and look at the pub/sub example.
Check your config settings again. It doesn't look like you're using external files; the sections are directly in app.config
I've been struggling with this problem for a whole day and do not know how to fix it. I have tried various things to resolve the issue but I am at a loss.
I have a project where I am attempting to use the LogReceiverServer from NLog to send and receive messages between 2 PCs. I followed this example here. Everything actually works fine, my WCF service starts up correctly, my client starts up correctly, even the sending of the message to log from client to server works. But, when I shut the client down, I get SocketExceptions thrown by the server for each message that was transmitted. I know this is due to the channel not being closed properly by the client. I cannot find where I must close the channel to prevent the exceptions being thrown by my server. I have read that to manually close the channel I must use
Channel.Close();
would that be correct and where would I put that?
I want to prevent these SocketExceptions. I have found this, but it does not seem to be the correct thing to do. Correct me if I am wrong, but would the solution not use the same principles?
Unless of course I am understanding this completely wrong...
Everything is done using the config files (App.Config and NLog.Config).
Here is my LogReceiverService Target from NLog.config:
<target xsi:type="LogReceiverService"
name="logreceiver"
endpointConfigurationName="LogReceiverClient"
endpointAddress="net.tcp://server:8888/NLogServices/LogReceiverServer/logreceiverserver" />
Here is my endpoint from my app.config:
<endpoint address="net.tcp://server:8888/NLogServices/LogReceiverServer/logreceiverserver"
binding="netTcpBinding"
bindingConfiguration="LogReceiverClient"
contract="NLog.LogReceiverService.ILogReceiverClient"
name="LogReceiverClient" />
Any help or advise would greatly be appreciated.
EDIT: Extended on problem description
OK, So first, here is the Service on my host pretty much as I got it from here:
/// <summary>
/// Log service server object that logs messages.
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class LogReceiverServer : ILogReceiverServer
{
public void ProcessLogMessages(NLogEvents nevents)
{
var events = nevents.ToEventInfo("Client.");
foreach (var ev in events)
{
var logger = LogManager.GetLogger(ev.LoggerName);
logger.Log(ev);
}
}
}
I then created this class, where I inherit from LogReceiverWebServiceTarget and override protected virtual WcfLogReceiverClient CreateWcfLogReceiverClient(); method. It is exactly the same as is found on GitHub here, except that I registered on the ProcessLogMessagesCompleted event where I close the 'client':
[Target("wcftarget")]
public class WcfTarget : LogReceiverWebServiceTarget
{
protected override WcfLogReceiverClient CreateWcfLogReceiverClient()
{
WcfLogReceiverClient client;
if (string.IsNullOrEmpty(EndpointConfigurationName))
{
// endpoint not specified - use BasicHttpBinding
Binding binding;
if (UseBinaryEncoding)
{
binding = new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement());
}
else
{
binding = new BasicHttpBinding();
}
client = new WcfLogReceiverClient(binding, new EndpointAddress(EndpointAddress));
}
else
{
client = new WcfLogReceiverClient(EndpointConfigurationName, new EndpointAddress(EndpointAddress));
/*commenting this out causes multiple socket exceptions on host*/
client.ProcessLogMessagesCompleted += client_ProcessLogMessagesCompleted;
}
return client;
}
private void client_ProcessLogMessagesCompleted(object sender, AsyncCompletedEventArgs e)
{
WcfLogReceiverClient client = sender as WcfLogReceiverClient;
if (client.State == CommunicationState.Opened)
{
(sender as WcfLogReceiverClient).Close();
}
}
}
The Logger in NLog.config is:
<logger name="*" writeTo="logreceiver" minlevel="Info" />
So then if I try to log like this:
class Program
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static void Main(string[] args)
{
logger.Info("foo");
}
}
my host gives prints this to Debug:
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
A first chance exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.dll
Will this have any impact on performance of the host over a long period of time?
The problem has been resolved: https://github.com/NLog/NLog/commit/138fd2ec5d94072a50037a42bc2b84b6910df641
I have a .NET Web solution with an Azure Cloud Service project and a single webrole. I deploy it to the East coast West coast data/compute centers for failover purposes and have been asked to automate the deployment using Powershell MSBuild and Jenkins.
The problem is i need to change the Sql Azure database connectionString in the Web.config prior to packaging and publishing to each deployment. Seems simple enough.
I understand that the webrole properties Settings tab allows you to add custom configuration properties to each deployment with a type of either "string" or "Connection String" but it looks like the "Connection String" option applies to only Blob, Table or Queue storage. If I use the "String" and give it an Sql Azure connection string type it writes it out as an key/value pair and Entity Framework and the Membership Provider do not find it.
Is there a way to add a per-deployment connection string setting that points to Sql Azure?
Thanks,
David
Erick's solution is completely valid and I found an additional way to solve the problem so I thought I'd come back and put it up here since I had such trouble finding an answer.
The trick is getting the Entity Framework and any providers like asp.net Membership/profile/session etc... to read the connection string directly from the Azure service configuration rather than the sites web.config file.
For the providers I was able to create classes that inherit the System.Web.Providers.DefaultMembershipProvider class and override the Initialize() method where I then used a helper class I wrote to retrieve the connection string using the RoleEnvironment.GetConfigurationSettingValue(settingName); call, which reads from the Azure service config.
I then tell the Membership provider to use my class rather than the DefaultMembershipProvider. Here is the code:
Web.config:
<membership defaultProvider="AzureMembershipProvider">
<providers>
<add name="AzureMembershipProvider" type="clientspace.ServiceConfig.AzureMembershipProvider" connectionStringName="ClientspaceDbContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
Note the custom provider "AzuremembershipProvider"
AzuremembershipProvider class:
public class AzureMembershipProvider : System.Web.Providers.DefaultMembershipProvider
{
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
string connectionStringName = config["connectionStringName"];
AzureProvidersHelper.UpdateConnectionString(connectionStringName, AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName),
AzureProvidersHelper.GetRoleEnvironmentSetting(connectionStringName + "ProviderName"));
base.Initialize(name, config);
}
}
And here's the helper class AzureProvidersHelper.cs:
public static class AzureProvidersHelper
{
internal static string GetRoleEnvironmentSetting(string settingName)
{
try
{
return RoleEnvironment.GetConfigurationSettingValue(settingName);
}
catch
{
throw new ConfigurationErrorsException(String.Format("Unable to find setting in ServiceConfiguration.cscfg: {0}", settingName));
}
}
private static void SetConnectionStringsReadOnly(bool isReadOnly)
{
var fieldInfo = typeof (ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
if (
fieldInfo != null)
fieldInfo.SetValue(ConfigurationManager.ConnectionStrings, isReadOnly);
}
private static readonly object ConnectionStringLock = new object();
internal static void UpdateConnectionString(string name, string connectionString, string providerName)
{
SetConnectionStringsReadOnly(false);
lock (ConnectionStringLock)
{
ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings["name"];
if (connectionStringSettings != null)
{
connectionStringSettings.ConnectionString = connectionString;
connectionStringSettings.ProviderName = providerName;
}
else
{
ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(name, connectionString, providerName));
}
}
SetConnectionStringsReadOnly(true);
}
}
The key here is that the RoleEnvironment.GetConfigurationSettingValue reads from the Azure service configuration and not the web.config.
For the Entity Framework that does not specify a provider I had to add this call to the Global.asax once again using the GetRoleEnvironmentSetting() method from the helper class:
var connString = AzureProvidersHelper.GetRoleEnvironmentSetting("ClientspaceDbContext");
Database.DefaultConnectionFactory = new SqlConnectionFactory(connString);
The nice thing about this solution is that you do not end up having to deal with the Azure role onstart event.
Enjoy
dnash
David,
A good option is to use the Azure configurations. If you right click on the Azure project, you can add an additional configuration. Put your connection string(s) in the correct configuration (e.g., ServiceConfiguration.WestCoast.cscfg, ServiceConfiguration.EastCoast.cscfg, etc).
In your build script, pass the TargetProfile property to MSBuild with the name of the configuration, and those settings will be built into the final cscfg.
Let me know if you run into any problems. I did the approach, and it took a few tries to get it working right. Some details that might help.
Erick
I use Visual Studio 2010 and MS SQL Server 2005. I'm new to WCF and I'm trying to learn while developing a small task managing application.
At the moment I have a solution with two console applications inside it
- the WCF service
- a client connecting to the WCF service to test out my code
The WCF service connects to a db using LINQ to SQL.
I've implemented an OperationContract which inserts something into the db behind the WCF service and it works.
I've implemented an OperationContract which returns a GUID from the WCF service to the client and that works too.
When I try to retrieve a list of List from the WCF service it fails with the following error:
"An error occurred while receiving the HTTP response to localhost:8000/TaskerTest/Service/operations. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server
InnerException: The underlying connection was closed: An unexpected error occurred on a receive.
My Contracts (the first two work. GetLists is the problem):
[ServiceContract(Namespace = "http://Tasker_Server")]
public interface IOperations {
[OperationContract]
string CreateList(string listName, string text);
[OperationContract]
string UpdateList(int idList, string listName, string text);
[OperationContract]
List<ToDoList> GetLists();
}
The implementation:
public List<ToDoList> GetLists() {
Guid token = OperationContext.Current.IncomingMessageHeaders.GetHeader<Guid>("token", "ns");
int? userID = CheckCache(token);
if (userID != null) {
List<ToDoList> lst = DBAccess.GetListsByUserId(userID.Value);
return lst;
}
else
return null;
}
The DB access code:
public static List<ToDoList> GetListsByUserId(int idCredential) {
TaskerModelDataContext tmdc = new TaskerModelDataContext();
List<ToDoList> lists = tmdc.ToDoLists.Where(entry => entry.id_Credential == idCredential).ToList<ToDoList>();
return lists;
}
And the client code (the WCF service is added as a Service Reference to the client project):
TaskerService.LoginClient test2 = new LoginClient();
string username = "usr1", password = "psw1";
test2.ClientCredentials.UserName.UserName = username;
test2.ClientCredentials.UserName.Password = password;
Guid result = Guid.Empty;
try {
result = test2.CheckCredentials(username, password);
Console.WriteLine("Login OK!");
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
TaskerService.OperationsClient client = new OperationsClient();
using(OperationContextScope contextScope = new OperationContextScope(client.InnerChannel)) {
Guid testToken = result; Console.WriteLine(testToken.ToString());
MessageHeader<Guid> mhg = new MessageHeader<Guid>(testToken);
MessageHeader untyped = mhg.GetUntypedHeader("token", "ns");
OperationContext.Current.OutgoingMessageHeaders.Add(untyped);
client.GetLists();
}
client.Close();
The client fails with the above exception on: client.GetLists();
I can provide any additional details as needed by readers.
UPDATE
I've turned tracing on with
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "SdrConfigExample.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
Then I've run Microsoft Service Trace Viewer on the generated log and got the following error:
There was an error while trying to serialize parameter . The InnerException message was 'Type 'System.DelegateSerializationHolder+DelegateEntry' with data contract name 'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System' is not expected
I've now added [DataContract] to the "ToDoList" class in my dbml file and now I don't receive an exception. I get the correct number of results in my client BUT the contents of each class seem to be empty.
My database classes were auto-generated using a dbml file (LINQ to SQL).
After I've added a [DataContract()] attribute to the ToDoList class in "TaskerModel.designer.cs" (the auto generated file) I didn't receive an exception anymore but the classes I retrieved on the client only had default values for each member.
I then added [DataMember()] attributes to all the members of ToDoList class AND added
[ServiceKnownType(typeof(ToDoList))]
to
[ServiceContract(Namespace = "http://Tasker_Server")]
public interface IOperations {
[OperationContract]
string CreateList(string listName, string text);
[OperationContract]
string UpdateList(int idList, string listName, string text);
[OperationContract]
List<ToDoList> GetLists();
}
And now it works. Don't know if there's an easier way to do it but it works now. If anybody knows of a better way to do this I would appreciate a comment.
In my case the problem was that there was a readonly property. Add an empty set(); and solve my problem.
I had the same error when calling my WCF restfull service. The problem seemed to be caused by the datatype I was returning as a response.
I returned JSON and my response-object had a variable with datatype DateTime. When I replaced the DateTime with string, the problem got away and a proper response returned. Probably it will help someone who rans into the same problem.
Replace:
[DataMember]
public DateTime dateFrom {get;set;}
with this
[DataMember]
public string dateFrom {get;set;}
My subscriber queue isn't picking up messages. It looks like they're ending up in the error queue.
The only unusual aspect to this is that the publisher is receiving messages which are generated from a website (and then a class library) which are then WCF'd to the publisher who publishes on behalf of the website/class library.
If I remove the publisher's <add Messages=""> then I get an error saying the publisher doesn't know where to route the messages.
No destination specified for message
Messages.ContactRequest. Message
cannot be sent. Check the
UnicastBusConfig section in your
config file and ensure that a
MessageEndpointMapping exists for the
message type.
Help! I've almost cut'n'pasted the WcfIntegration and PubSub samples, so I don't know why it isn't working!
PUBLISHER:
<MsmqTransportConfig
InputQueue="RSApp_InputQueue"
ErrorQueue="error"
NumberOfWorkerThreads="1"
MaxRetries="5"
/>
<UnicastBusConfig
DistributorControlAddress=""
DistributorDataAddress=""
ForwardReceivedMessagesTo="">
<MessageEndpointMappings>
<add Messages="Messages" Endpoint="RSApp_InputQueue" />
</MessageEndpointMappings>
</UnicastBusConfig>
SUBSCRIBER:
<!-- SUBSCRIBER -->
<MsmqTransportConfig
InputQueue="RSApp_SubscriberQueue"
ErrorQueue="error"
NumberOfWorkerThreads="1"
MaxRetries="5"
/>
<UnicastBusConfig
DistributorControlAddress=""
DistributorDataAddress=""
ForwardReceivedMessagesTo="">
<MessageEndpointMappings>
<add Messages="Messages" Endpoint="RSApp_InputQueue" />
</MessageEndpointMappings>
</UnicastBusConfig>
p.s. does the WCF endpoint automatically created by nservicebus also automatically bus.publish<>() the message?
p.s. I don't understand what I need to do with this:-
[ServiceContract]
public interface IContactRequestService
{
[OperationContract(Action = "http://tempuri.org/IWcfServiceOf_ContactRequest_ErrorCodes/Process",
ReplyAction = "http://tempuri.org/IWcfServiceOf_ContactRequest_ErrorCodes/ProcessResponse")]
ErrorCodes Process(Messages.ContactRequest request);
}
Here's my client calling code:-
public void MakeContactRequest(int id, Guid RequestingUserId, Guid RequesteeUserId, Messages.ContactRequestType type)
{
//get extra information
var u = Services.UserService.FetchUserProfile(id);
//add it to local database
var RequestIdentifier = Guid.NewGuid();
//create message
var req = new ContactRequest()
{
contactRequestType = type,
Name = u.DisplayName,
RequestCreationDate = DateTime.Now,
TagLine = u.Tagline,
RequesterUserId = RequestingUserId,
RequesteeUserId = RequesteeUserId,
RequestIdentifier = RequestIdentifier
};
//drop it onto distributed message queue
IContactRequestService client = ChannelFactory.CreateChannel();
try
{
ErrorCodes returnCode = client.Process(req);
}
finally
{
try
{
((IChannel)client).Close();
}
catch
{
((IChannel)client).Abort();
}
}
}
What is wierd is that putting a message on the bus without using WCF works a treat!!
public void Run()
{
Console.WriteLine("This will publish IEvent and EventMessage alternately.");
Console.WriteLine("Press 'Enter' to publish a message.To exit, Ctrl + C");
bool publishIEvent = true;
while (Console.ReadLine() != null)
{
var eventMessage = publishIEvent ? Bus.CreateInstance<ContactRequest>() : new ContactRequest();
Bus.Publish(eventMessage);
Console.WriteLine("Published event ");
publishIEvent = !publishIEvent;
}
NSB will not do the Publish() for you, you have to put that in your message handler just like any NSB endpoint. Exposing the endpoint via WCF doesn't require you to do anything except implement the abstract class WcfService<TRequest,TResponse>. You shouldn't need that other code, since NSB handles it internally. Technically the Publisher shouldn't need a message mapping since it manages subscriptions internally so I'm not sure why you are getting an error there.
If the messages are in the error queue, then you should see an exception in the log. You many want to configure the logging to point to a file or something durable if you are using the Lite(default profile).