NserviceBus. How to start several buses in different AppDomains? - nservicebus

I want to have several buses in one process. I googled about this and found that it is possible only if having several AppDomains. But I cannot make it work.
Here is my code sample (I do everything in one class library):
using System;
using System.Diagnostics;
using System.Reflection;
using MyMessages;
using NServiceBus;
using NServiceBus.Config;
using NServiceBus.Config.ConfigurationSource;
namespace Subscriber1
{
public class Sender
{
public static void Main()
{
var domain = AppDomain.CreateDomain("someDomain", AppDomain.CurrentDomain.Evidence);
domain.Load(Assembly.GetExecutingAssembly().GetName());
domain.CreateInstance(Assembly.GetExecutingAssembly().FullName, typeof (PluginBusCreator).FullName);
//here I have some code to send messages to "PluginQueue".
}
}
public class PluginBusCreator
{
public PluginBusCreator()
{
var Bus = Configure.With(
Assembly.Load("NServiceBus"), Assembly.Load("NServiceBus.Core"),
Assembly.LoadFrom("NServiceBus.Host.exe"), Assembly.GetCallingAssembly())
.CustomConfigurationSource(new PluginConfigurationSource())
.SpringFrameworkBuilder()
.XmlSerializer().MsmqTransport()
.UnicastBus().LoadMessageHandlers<First<SomeHandler>>().CreateBus().Start();
}
protected IBus Bus { get; set; }
}
class PluginConfigurationSource : IConfigurationSource
{
public T GetConfiguration<T>() where T : class
{
{
if (typeof (T) == typeof (MsmqTransportConfig))
return new MsmqTransportConfig
{
ErrorQueue = "error",
InputQueue = "PluginQueue",
MaxRetries = 1,
NumberOfWorkerThreads = 1
} as T;
return null;
}
}
}
public class SomeHandler : IHandleMessages<EventMessage1>
{
public void Handle(EventMessage1 message)
{
Debugger.Break();
}
}
}
And I don't get handler invoked.
If you have any ideas, please help. I'm fighting this problem a lot of time.
Also if full code need to be published, please tell.
I need several buses to solve the following problem :
I have my target application, and several plugins with it. We decided to make our plugins according to service bus pattern.
Each plugin can have several profiles.
So, target application(it is web app.) is publishing message, that something has changed in it. Each plugin which is subscribed to this message, need to do some action for each profile. But plugin knows nothing about its profiles (customers are writing plugins). Plugin should only have profile injected in it, when message handling started.
We decided to have some RecepientList (pattern is described in "Enterprise Integration Patterns"), which knows about plugin profiles, iterates through them and re-send messages with profiles injected.(So if plugin has several profiles, several messages will be sent to it).
But I don't want to have each plugin invoked in a new process. Perfectly I want to dynamically configure buses for each plugin during start. All in one process. But it seems I need to do it in separate AppDomains. So I have a problem described above:-).

Sergey,
I'm unclear as to why each plugin needs to have its own bus. Could they all not sit on the same bus? Each plugin developer would write their message handlers as before, and the subscriptions would happen automatically by the bus.
Then, also, you wouldn't need to specify to load each of the NServiceBus DLLs.
BTW, loading an assembly by name tends to cause problems - try using this to specify assemblies:
typeof(IMessage).Assembly, typeof(MsmqTransportConfig).Assembly, typeof(IConfigureThisEndpoint).Assembly

Related

Xamarin.Forms Communication Between Two Pages Within Same App on Different Devices

Technologies, frameworks and devices I'm using:
Framework: Xamarin.Forms
IDE: Visual Studio 2022
Physical Device (smartphone): Zebra TC26 (Android 10)
Physical Device (smartwatch): Samsung Galaxy Watch4 (Android 11)
Problem definition
Currently I have a test Xamarin.Forms project that consists of two different UIs (XAML files):
User Interface 1: HomePage.XAML - This screen should be displayed on the smartphone
User Interface 2: WatchScreen.XAML - This screen should be displayed on the smartwatch
With code below I make sure HomePage.XAML is deployed to a smartphone and watchscreen is deployed to a smartwatch:
Page homePage = new NavigationPage(new HomePage());
// BuildVersionCodes.R is a reference to Android version 11 (mostly now used by Wear OS 3.x)
if (Build.VERSION.SdkInt == BuildVersionCodes.R)
{
// SM-R870 is a reference to the Samsung Galaxy Watch4
// Note: This is needed to ensure the UI is specific to the UI of a smartwatch
if (Build.Model == "SM-R870")
{
Page watchScreen = new NavigationPage(new WatchScreen());
MainPage = watchScreen;
}
}
else
{
MainPage = homePage;
}
Now I want to make these pages on different devices communicate with each other. HomePage.xaml exists within the main Xamarin.Forms project as well as WatchScreen.xaml.
The way I want them to communicate with each other is by sending a message or something. A Xamarin.Forms project also comes with a native project. In this native Xamarin.Android project I try to retrieve inside the MainActivity.cs the button that exists within the main project by using (in WatchScreen.xaml this button exists and in WatchScreen.xaml.cs I have a method that gives this button back).
Method in WatchScreen.xaml.cs that gives button back:
public Button GetSendButtonFromWearableUI() => btnSendMessage;
In MainActivity.cs I get this method by using:
Button button = (App.Current.MainPage.Navigation.NavigationStack.LastOrDefault() as WatchScreen)
.GetSendButtonFromWearableUI();
Whenever I click on the button by doing this:
button.Clicked += delegate
{
SendData();
};
Some data should be sent from MainActivity.cs and catched by HomePage.xaml and displayed on it. I tried several approaches but I didn't succeed in achieving what needs to happen.. Therefore, I'm wondering if you guys could help me out with this and would be much appreciated.
In the meantime I've been investigating this issue and came up with a solution. Follow steps below to get the same result. To make this solution work I've combined the Wearable Data Layer API from Google and MessagingCenter from Microsoft.
Also the example below shows only the communication from the smartwatch to the smartphone. In order to reverse processes you can put the send button on the HomePage instead of the smartwatch screen and make sure to subscribe to the correct messages.
One last note: keep in mind that code used below from Google is deprecated but it still works...
References used to make this work:
Syncing Data Between Wearable and Handheld Devices Using Xamarin in Android
Installed dependencies on the Xamarin.Android project within Xamarin.Forms project:
Xamarin.Android.Support.v4
Xamarin.GooglePlayServices.Base
Xamarin.GooglePlayServices.Wearable
MessageKeys.cs
This class is used to declare message keys that are being used to send and receive messages between devices.
public class MessageKeys
{
public const string Smartwatch = "Smartwatch";
public const string Smartphone = "Smartphone";
}
Xamarin.Forms (Base project) - App.xaml.cs
In the App.xaml.cs, as pointed out earlier, I'm making sure the wearable UI displays WatchScreen.xaml and any other devices display regular Android UI -> HomePage.xaml.
Xamarin.Forms (Base project) - WatchScreen.xaml.cs
Send message from Wearable device to Android smartphone.
private void btnSendMessage_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch);
}
Xamarin.Forms (Base project) - HomePage.xaml.cs
public HomePage()
{
InitializeComponent();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartphone, (sender) =>
{
DisplayAlert("Message", "Wearable message received!", "OK");
});
}
Xamarin.Forms (Native Android Project) - MainActivity.cs
Within MainActivity.cs I implement the following interfaces:
public class MainActivity : WearableActivity, DataClient.IOnDataChangedListener,
GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener
Variables:
private GoogleApiClient client;
const string syncPath = "/[project name]/[subdirectory for watch]";
Internal class 'MessageReceiver' for receiving broadcast messages:
[BroadcastReceiver]
public class MessageReciever : BroadcastReceiver
{
MainActivity main;
public MessageReciever() { }
public MessageReciever(MainActivity owner) { this.main = owner; }
public override void OnReceive(Context context, Intent intent)
{
main.ProcessMessage(intent);
}
}
Registering receiver (to receive through Wearable Data Layer API), creating Google Client and Subscribing to smartwatch message (to retrieve message through MessagingCenter)
protected override void OnCreate(Bundle bundle)
{
IntentFilter filter = new IntentFilter(Intent.ActionSend);
MessageReciever receiver = new MessageReciever(this);
LocalBroadcastManager.GetInstance(this).RegisterReceiver(receiver, filter);
client = new GoogleApiClient.Builder(this, this, this)
.AddApi(WearableClass.Api)
.Build();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch, (sender) =>
{
SendData();
});
}
ProcessMessage method: sends received message from wearable to smartphone
public void ProcessMessage(Intent intent)
{
// For now I'm not sending the payload...
string message = intent.GetStringExtra("WearMessage");
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartphone);
}
SendData(), OnStart(), OnStop(), OnDataChanged (didn't do anything with this part, because this is to receive messages outside the project and I don't need it for now), OnConnected(), OnConnectionSuspended(), OnConnectionFailed():
See the reference to see what code has been used, since code is exactly the same... P.S.: one thing for SendData has been changed. If you want to keep sending data, remove 'client.Disconenct()' from finally after the try and catch block.
Xamarin.Forms (Native Android Project) - WearableService inherits from WearableListenerService:
WearableService is a new class and created within the native project. Also for this part see the reference, because it's the exact same code being used within my project.
To get an overall overview of what's happening, I've visualized this in the diagram below: (example shows how communication works from smartwatch to smartphone)
If you want to communicate from smartphone to smartwatch, you could do something like this:
That's it guys. Now you will receive messages within the same application using the Wearable Data Layer API and MessagingCenter. Instead of having separate projects, we just use separate UIs to make this happen...

Can I have per AppDomain Environment Variables in C#/.net?

In a multi appdomain setup, is there a way to make SetEnvironementVariables and Get.... work within the appdomain only, so each appdomain can have different values for the same variable?
No. :(
This example:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var newDomain = AppDomain.CreateDomain("Alternative");
Proxy proxyObj = (Proxy)newDomain.CreateInstanceAndUnwrap(typeof(Proxy).Assembly.GetName().FullName,
typeof(Proxy).FullName);
Environment.SetEnvironmentVariable("HELLO_MSG", "Hello World", EnvironmentVariableTarget.Process);
proxyObj.ShowEnvironmentVariable();
Console.ReadKey();
}
}
class Proxy : MarshalByRefObject
{
public void ShowEnvironmentVariable()
{
var msg = Environment.GetEnvironmentVariable("HELLO_MSG");
Console.WriteLine(String.Format("{0} (from '{1}' AppDomain)", msg, AppDomain.CurrentDomain.FriendlyName));
}
}
}
Will output:
Hello World (from 'Alternative' AppDomain)
The process is the most specific level of encapsulation for environment variables, and AppDomains will still "live inside" the same process.
Note that this will happen for all other process-level information (such as Directory.GetCurrentDirectory(), command-line args, etc.
One possible solution would create worker processes (".exe" applications spawned from the main process), but that will certainly add some complexity to your application.

Injecting Variables into a running Process

Is there a way to inject a variable into a running process without a process listening for RPC requests?
For example if a process was running and using an environment variable, could I change that environment variable at runtime and make the process use the new value?
Are there alternative solutions for dynamically changing variables in a running process? Assume that this process is like a PHP process or a Javascript (node.js) process so I can change the source code... etc.
I think this is similar to passing state or communicating to another process, but I need a really lightweight way of doing so, without going over the network or using libraries or preferably not setting up an RPC server.
Solution does not have to be cross-platform. Prefer Linux.
You can do it it java. Imagine this is your thread class:
public void ThreadClass extends Thread {
Boolean state;
ThreadClass(Boolean b) {
state = b;
}
public void StopThread() {
state = false;
}
public void run() {
while(state) { //Do whatever you want here}
}
}
Now all you have to do is start this thread from your main class:
ThreadClass thread = new ThreadClass(true);
thread.start();
And if you want to change the value of state, call the StopThread method in the thread like so:
try {
thread.StopThread();
} catch (InterruptedException ex) {
Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
}
This will change the state of the Boolean while the thread is running.
It appears that local IPC implementations like shared memory is the way to go: Fastest technique to pass messages between processes on Linux?

How does HiveInterruptUtils.interrupt() work?

I've been reading the hive source code recently, but I'm confused by this interrupt(). I want to know how it interrupts the current hive command.The location of this function is in CliDriver.processLine().
In the implementation of HiveInterruptUtils http://people.apache.org/~hashutosh/hive-clover/common/org/apache/hadoop/hive/common/HiveInterruptUtils.html, find this:
public static void interrupt() {
synchronized (interruptCallbacks) {
for (HiveInterruptCallback resource :
new ArrayList<HiveInterruptCallback>(interruptCallbacks)) {
resource.interrupt();
}
}
}
That might interrupts all resources previously added to the HiveInterruptCallback list.
And also the HiveInterruptCallback, http://people.apache.org/~hashutosh/hive-clover/common/org/apache/hadoop/hive/common/HiveInterruptCallback.html#HiveInterruptCallback, is an interface.
public interface HiveInterruptCallback {
/**
* Request interrupting of the processing
*/
void interrupt();
}
The previously registered resources implement HiveInterruptCallback interrupt() method, so the HiveInterruptUtils.interrupt() behavior depends on the specific resource implementation.

Apache Camel : GBs of data from database routed to JMS endpoint

I've done a few small projects in camel now but one thing I'm struggling to understand is how to deal with big data (that doesn't fit into memory) when consuming in camel routes.
I have a database containing a couple of GBs worth of data that I would like to route using camel. Obviously reading all data into memory isn't an option.
If I were doing this as a standalone app I would have code that paged through the data and send chunks to my JMS enpoint. I'd like to use camel as it provides a nice pattern. If I were consuming from a file I could use the streaming() call.
Also should I use camel-sql/camel-jdbc/camel-jpa or use a bean to read from my database.
Hope everyone is still with me. I'm more familiar with the Java DSL but would appreciate any help/suggestions people can provide.
Update : 2-MAY-2012
So I've had some time to play around with this and I think what I'm actually doing is abusing the concept of a Producer so that I can use it in a route.
public class MyCustomRouteBuilder extends RouteBuilder {
public void configure(){
from("timer:foo?period=60s").to("mycustomcomponent:TEST");
from("direct:msg").process(new Processor() {
public void process(Exchange ex) throws Exception{
System.out.println("Receiving value" : + ex.getIn().getBody() );
}
}
}
}
My producer looks something like the following. For clarity I've not included the CustomEndpoint or CustomComponent as it just seems to be a thin wrapper.
public class MyCustomProducer extends DefaultProducer{
Endpoint e;
CamelContext c;
public MyCustomProducer(Endpoint epoint){
super(endpoint)
this.e = epoint;
this.c = e.getCamelContext();
}
public void process(Exchange ex) throws Exceptions{
Endpoint directEndpoint = c.getEndpoint("direct:msg");
ProducerTemplate t = new DefaultProducerTemplate(c);
// Simulate streaming operation / chunking of BIG data.
for (int i=0; i <20 ; i++){
t.start();
String s ="Value " + i ;
t.sendBody(directEndpoint, value)
t.stop();
}
}
}
Firstly the above doesn't seem very clean. It seems like the cleanest way to perform this would be to populate a jms queue (in place of direct:msg) via a scheduled quartz job that my camel route then consumes so that I can have more flexibility over the message size received within my camel pipelines. However I quite liked the semantics of setting up time based activations as part of the Route.
Does anyone have any thoughts on the best way to do this.
In my understanding, all you need to do is:
from("jpa:SomeEntity" +
"?consumer.query=select e from SomeEntity e where e.processed = false" +
"&maximumResults=150" +
"&consumeDelete=false")
.to("jms:queue:entities");
maximumResults defines a limit of how many entities you get per query.
When you finish the processing of an entity instance, you need to set e.processed = true; and persist() it, so that the entity won't be processed again.
One way to do that is with the #Consumed annotation:
class SomeEntity {
#Consumed
public void markAsProcessed() {
setProcessed(true);
}
}
Another thing, you need to be careful with is how you serialize the entity before sending it to the queue. You might need to use an enricher between the from and to.