I would like to know if there's a way to configure BizTalk to have an orchestration that wouldn't constantly poll a folder for a file, but would rather check for a file "on-demand".
By "on-demand", I mean that I need BizTalk to "wait" for a web service call (via WCF port) and then go fetch a file in an FTP folder and start the orchestration.
Is it something feasible? I read that "Dynamic ports" could be used for that, is it true?
Thanks,
Alex
You could dynamically create a FILE (or FTP) receive location in an orchestration that is activated by the WCF Receive Port.
Brian Loesgen blogged a simple example of code that could be called by your orchestration to create receive locations. If the server and folder names do not change from one call to the next, then you could use the same receive location each time and just activate/deactivate it at run-time.
Here is another Stack Overflow question that specifically addresses activating a receive location in code: Is there a way to automate turning a BizTalk Receive Location on or off through code?
Create a new class project in Visual Studio, add in a reference to Microsoft.BizTalk.ExplorerOM, write a few lines of code, and you've got your helper assembly!
Here's a sample from MSDN to create and configure an HTTP receive location:
private void CreateAndConfigureReceiveLocation()
{
BtsCatalogExplorer root = new BtsCatalogExplorer();
try
{
root.ConnectionString = "Server=.;Initial Catalog=BizTalkMgmtDb;Integrated Security=SSPI;";
//First, create a new one way receive port.
ReceivePort myreceivePort = root.AddNewReceivePort(false);
//Note that if you dont set the name property for the receieve port,
//it will create a new receive location and add it to the receive //port.
myreceivePort.Name = "My Receive Port";
//Create a new receive location and add it to the receive port
ReceiveLocation myreceiveLocation = myreceivePort.AddNewReceiveLocation();
foreach(ReceiveHandler handler in root.ReceiveHandlers)
{
if(handler.TransportType.Name == "HTTP")
{
myreceiveLocation.ReceiveHandler = handler;
break;
}
}
//Associate a transport protocol and URI with the receive location.
foreach (ProtocolType protocol in root.ProtocolTypes)
{
if(protocol.Name == "HTTP")
{
myreceiveLocation.TransportType = protocol;
break;
}
}
myreceiveLocation.Address = "/home";
//Assign the first receive pipeline found to process the message.
foreach(Pipeline pipeline in root.Pipelines)
{
if(pipeline.Type == PipelineType.Receive)
{
myreceiveLocation.ReceivePipeline = pipeline;
break;
}
}
//Enable the receive location.
myreceiveLocation.Enable = true;
myreceiveLocation.FragmentMessages = Fragmentation.Yes;//optional property
myreceiveLocation.ServiceWindowEnabled = false; //optional property
//Try to commit the changes made so far. If the commit fails,
//roll-back all changes.
root.SaveChanges();
}
catch(Exception e)
{
root.DiscardChanges();
throw e;
}
}
Unfortunately the only thing BizTalk provides for this is something called a service window which allows you to schedule receive locations to turn on and off.
However it's very restrictive, with a single window per 24 hour period only. Also you have to know the times upfront.
Dynamic ports only apply to the send of messages, not for receiving them.
If you control the web service in any way, then you can always loosely couple the two systems using a queue or a database table, i.e. change the web service so that when a call is made, a message for BizTalk is placed in a queue/table. Then hook up your orchestration to the same queue/table so that it fetches a file "on demand". This scenario may not be entirely appropriate in your situation, but that's probably the closest you can get...
Related
In a Spring Boot Kafka stream-processing app using Spring Cloud Function, how can I shut down the application (to stop it receiving any further messages) but only after responding to the current message?
The scenario is this: we have an app that processes a message which contains a reference to some file. We handle this by interrogating the given file's content using some third party libraries and responding with some data we extract from the file. In some rare cases certain files can cause the external libraries to hang. So we call these libraries on a background thread and time out if it takes too long. We need to respond to Kafka for this message (with some JSON detailing the error) so that Kafka doesn't send it to any other instance of our app (as it'll probably cause that instance to hang as well). But we then want this instance of our Spring Boot app to shut down, as we can't cleanly recover from the hang in the 3rd party library (we could get resource or memory leaks otherwise). Another instance will then be automatically brought up by Kubernetes or Docker Swarm or whatever.
I'm not sure if it's relevant, but we're using Spring Cloud Function, and we're joining two streams: the "file" stream, where each message contains a reference to the file to process, and a GlobalKTable with some config info. The code looks like this (in Kotlin):
// The service we use to run the process on a background thread
private val executorService = Executors.newFixedThreadPool(1)
#Bean
fun process() = BiFunction<KStream<String, FileInfo>,
GlobalKTable<String, Config>,
KStream<String, FileInterrogationResult>> { fileStream, configTable ->
requestStream.join(
configTable,
{ _, file -> file.configId },
{ file, config ->
try {
// Process the file using the 3rd party libraries.
val result = executorService.submit(theThirdPartyLibExtractionFunction)
.get(someTimeout, TimeUnit.MILLISECONDS)
// Success: return some FileInterrogationResult object wrapping the result from above.
} catch (e: TimeoutException) {
// Return some FileInterrogationResult object with error details.
// TODO: Here we know that after this function completes the app should shut down. How do we do this?
} catch (e: Throwable) {
// Return some FileInterrogationResult object with error details.
}
}
)
You can use Actuator endpoints to stop/start/pause/resume as well as monitor individual bindings.
Once enabled you can simply use curl to manage the bindings.
For example
curl -d '{"state":"STOPPED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName
The exact instruction on how to do it available here
if I send a request, and I expect the response to come trough SignalR, is it possible to test this using a LoadTest or PerformanceTest in Visual Studio?
Short answer: Yes
I've done this several times in CodedWebTests but it would also be possible to do in a declarative WebTest. You can use a custom PreWebTest Event Handler to create your signalR client and connect to your SignalR hub. What you choose to do with the signalR notification is up to you but I like to save it to the WebTestContext as well as display it on the test results screen using the AddCommentToResult method.
The method below creates a hubConnection invokes the "addToGroup" function on the hub and then tells the client what to do when it receives a message.
using Microsoft.AspNet.SignalR.Client;
public class SignalRPlugin : WebtTestPlugin
{
public override void PreWebTest(object sender, PreWebTestEventArgs e)
{
var hubConnection = new HubConnection("yourSignalRUrl");
var hubProxy = hubConnection.CreateHubProxy("notifications");
hubConnection.Start().Wait();
hubProxy.Invoke("addToGroup", "me");
hubProxy.On<string>("message", s =>
{
e.Webtest.AddCommentToResult(s);
e.Webtest.Context.Add("signalRMessages", s);
});
}
}
Use it by attaching the event handler in your test constructor.
public MyWebTest()
{
PreWebTest += new SignalRPlugin().PreWebTest;
}
Then once you have the signalR messages you can use a custom validation rule to validate that the response was received. Just have a while loop checking the WebTestContext for the "signalRMessages" key. I strongly suggest making sure you add a timeout feature so you are not waiting forever if the messages never come in.
The other option if you are writing CodedWebTests is to create a WaitForNotifications method that basically does the same thing as the validation rule. The advantage with this is that you can use an extraction rule to get data out of the last response and then use that data in validating your signalR messages. If you still need to fail a test in your WaitForNotification method use WebTest.InternalSetOutcome(Outcome.Fail);
The best way to load test a SignalR application is by building on the crank project included in the source.
This is a simple ramp up solution built with the .Net client but it is relatively easy to modify to call whatever hub methods you require and to analyse the responses.
You can always attach the Visual Studio profiler to your iis express instance to get detailed profiling data if required.
Ive got a WCF service which has multiple web methods in it. I want to be able to intercept the request on all methods and look at the Ip address. Id rather not put the logic into a method call at the top of each called web method is there a way to intercept all calls to these methods from one place?
If it was a page I would write a base page object but im nout sure if there are events raised on a wcf call?
WCF allows you to implement interceptors that are added to the stack. See this link for an example. I´m not sure whether this allows you the extract the senders IP but I think it´s worth a try.
You can implement IDispatchMessageInspector and do something like this.
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
{
RemoteEndpointMessageProperty remoteEndpoint = request.Properties
[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
//remoteEndpoint.Address will give you the address.
return null;
}
You can use Custom Behaviors, they are part of WCF Extensibility features. Here's more information: Extending WCF with Custom Behaviors
There's a clever way to do this with the ServiceAuthorizationManager, and it's far easier than all the seriously hard work of the IDispatchMessageInspector.
Create a class in your WCF Service project like so:
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
string classMethod = operationContext.RequestContext.RequestMessage.Headers.Action;
if (classMethod.Contains("/transfer/Get"))
{
return true; // because someone is simply updating a client service reference
}
Console.WriteLine("Class Method Call: {0}",classMethod);
// do something with operationContext here as you need to inspect stuff
// return true if you want this class method call to succeed and go through
// return false if you want this class method to fail on the client
return true;
}
}
Then, in your service, right before your host.Open() call, add the link to MyServiceAuthorizationManager.
ServiceHost host = new ServiceHost(typeof(MyProject.Service1));
host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
host.Open();
Now when you test your client connections, you'll notice that the console outputs what class method was called. You can also work against all the stuff in the operationContext object.
One way I use this is for a security header check. In my client, I add a header. Then, in the service, in this CheckAccessCore() call, I verify that this custom header exists. If it doesn't, then I return false. This is one more layer of protection that keeps the hackers out, and is great for the limited security in Named Pipes configurations too. If you're wanting to also do that, then click here for more information on how to add custom headers that automatically get sent on every client's method call on the service.
And note, among all this, I didn't have to mess with behaviors, claims, listeners, or message dispatches. I also didn't need to edit my WCF Configuration.
Note the string check for /transfer/Get above. This is important if you're doing header checks as a security mechanism like I was. If you don't have that condition and return true, then your WCF client IDE can't update its ServiceReference because the IDE doesn't know about that extra header (if you're adding a custom header and not specifying that header in the WCF client's app.config). Otherwise, you'll get an error The URI prefix is not recognized.
I have a shared object created in WebScope. when I start the server and clients connect for the first time, it sends change and delete events just fine. but after that it only sends clear event. any ideas?
It seems that you use SyncEvent.changeList property, but what for?
I suggest you to iterate over data via SharedObject.data or SyncEvent.data properties.
var busySO:SharedObject = ...;
for each (var obj:Object in busySO.data) {
...
}
I've got a problem here.
I've got an ASP.net website hosting a silverlight 2 application.
I'd like the site to communicate to and fro from the silverlight app, and I'm doing this via http requests. Incidentally, if anyone knows a better way, please do tell me.
My server's got the following http listener set up. I copied this from a tutorial site somewhere, since it's mainly experimentation at the moment :
HttpListener listener = new HttpListener ( );
listener.Prefixes.Add("http://localhost:4531/MyApp/");
listener.Start( );
// Wait for a client request:
HttpListenerContext context = listener.GetContext( );
// Respond to the request:
string msg = "You asked for: " + context.Request.RawUrl;
context.Response.ContentLength64 = Encoding.UTF8.GetByteCount (msg);
context.Response.StatusCode = (int) HttpStatusCode.OK;
using (Stream s = context.Response.OutputStream)
using (StreamWriter writer = new StreamWriter (s))
writer.Write (msg);
listener.Stop( );
I'm using the following code to send a request :
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
b.Content = "Hello World";
Uri serviceUri = new Uri("http://localhost:4531/MyApp/");
WebClient downloader = new WebClient();
downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TestDownloadStoriesCompleted);
downloader.DownloadStringAsync(serviceUri);
}
void TestDownloadStoriesCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
TextBox1.Text = e.Result;
}
}
My problem is that I can connect to the webserver from a console application using pretty much the same code (I tested it by setting a breakpoint in the code), however nothing happens when I click the button in silverlight. (I've added the "Hello World" to test that I am indeed connecting the delegate to the button.)
I've read that silverlight needs policies to connect via webclient, but it shouldn't be the case if I'm using the same server and the same domain for both the server and the silverlight application!
Thanks for all your replies!
EDIT : I am recieving this exception :
System.Security.SecurityException ---> System.Security.SecurityException: Security error.
Also, based on what I'm reading apparently to be site-of-origin, the deployment URI of the xap and the request URI must also be of the same port.
However, when I set the properties for the server to be hosted on a specific port, and I set the listener to listen to that same port, it fails with the message that The process cannot access the file because it is being used by another process. I assume it is because the http listener can't listen to the same port being used to host it :|
But then how can I make Silverlight perform host of origin webclient requests?
Since this is only a test add an "else TextBox1.Text=e.Error.ToString();" in your TestDownloadStoriesCompleted handler to see what error you get.
EDIT:
You can't host both the asp.net app and your listener on the same port - you could fix this by using a different port and serving a clientaccesspolicy.xml from your httplistener.
However I think it would make more sense for you to take a look at WCF web services (you add the svc to your asp.net app). Here's a sample.
you can use tools like http://www.fiddler2.com/fiddler2/
to actually see what is going on during the request....
This can give some help for further debugging...
I am now using HTTP handlers for communication. It seems that they will work fine enough for my purpose, although I still want to try out some WCF.