How to host the Windows Workflow as a Web service(.svc)? - workflow

I am trying to host the windows workflow as a web service, below is the sample workflow that I built and would like to host as a web service(.svc), can you please suggest the required steps?
using System;
using System.ServiceModel.Activities;
using System.Activities;
using System.ServiceModel;
using System.Activities.Statements;
namespace DemoWF
{
public class _25_LeaveRequest
{
public WorkflowService GetInstance()
{
WorkflowService service;
Variable<int> empID = new Variable<int> { Name = "empID" };
Variable<int> requestID = new Variable<int> { Name = "requestID" };
Receive receiveLeaveRequest = new Receive
{
ServiceContractName = "ILeaveRequestService",
OperationName = "ApplyLeave",
CanCreateInstance = true,
Content = new ReceiveParametersContent
{
Parameters ={
{"empID",new OutArgument<int>(empID)}
}
}
};
SendReply replyLeaveRequestID = new SendReply
{
Request = receiveLeaveRequest,
Content = new SendParametersContent
{
Parameters ={
{"requestID",new InArgument<int>(requestID)},
},
},
};
Sequence workflow = new Sequence()
{
Variables = { empID, requestID },
Activities = {
new WriteLine{Text="WF service is starting..."},
receiveLeaveRequest,
new WriteLine{
Text=new InArgument<string>(aec=> "Emp ID="+empID.Get(aec).ToString())
},
new Assign<int>{
Value=new InArgument<int>(5),
To=new OutArgument<int>(requestID)
},
new WriteLine{
Text=new InArgument<string>(aec=> "Request ID="+requestID.Get(aec).ToString())
},
replyLeaveRequestID
},
};
service = new WorkflowService
{
Name = "AddService",
Body = workflow
};
return service;
}
}
Right now, it is self hosted as highlighted below
namespace DemoWF
{
class Program
{
static void Main(string[] args)
{
LeaveRequest();
}
private static void LeaveRequest()
{
_25_LeaveRequest receiveAndReplyWorkflow = new _25_LeaveRequest();
WorkflowService wfService = receiveAndReplyWorkflow.GetInstance();
Uri address = new Uri("http://localhost:8000/WFServices");
WorkflowServiceHost host = new WorkflowServiceHost(wfService, address);
try
{
Console.WriteLine("Opening Service...");
host.Open();
Console.WriteLine("WF service is listening on " + address.ToString() + ", press any key to close");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("some thing bad happened" + e.StackTrace);
}
finally
{
host.Close();
}
}
}
}

The quickest way would be to create a WCF Workflow Service Application.
You'll get a workflow designer where you can drag and drop the activities you need:
And if you run the project in Visual Studio, you'll get an auto-generated WSDL with your service operation(s):
And also it will bring up Visual Studio's WCF Test Client tool:
You can create a workflow-based service that handles multiple methods by using the Pick Branch activity. Each branch would then have a Receive and Send Reply activity, with the receive activity moved to the trigger section and the send reply activity in the action part.
Each trigger would be for a specific operation on the service. In the following example, I define two operations: MyFirstOperation and MySecondOperation.
Below is what the WCF test client tool will show with multiple operations exposed from the workflow:
Hopefully that gets you started. The topic of standing up workflow-based WCF services can get quite involved. :)

Related

I ran my program as BackgroundService but the service does not run the code

I've created program in C# Worker Service .NET 7.0. This program listening all incoming GET request and save this requests as URI and URL into Log.txt file. I used Titanium Web Proxy to listen all incoming requests from server. Program is working correctly but problem apear when im trying to run it as windows service. To do this im publishing my program into folder, next using command prompt Im creating service choosing .exe file from published folder and starting process with "sc start ServiceName" command. Service is running but its not working at all.
Here is my Program.cs code:
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Hosting;
using Serilog.Extensions.Logging;
namespace WorkerService5
{
public class Program
{
static async Task Main(string[] args)
{
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.UseWindowsService()
.UseSerilog()
.Build();
await host.RunAsync();
}
}
}
Here is my Worker.cs code:
using System.Net;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
using Serilog;
using Microsoft.Extensions.Hosting;
namespace WorkerService5
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public Worker(ILogger<Worker> logger, IHostApplicationLifetime hostApplicationLifetime)
{
_logger = logger;
_hostApplicationLifetime = hostApplicationLifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () =>
{
try
{
var proxyServer = new ProxyServer(userTrustRootCertificate: false);
proxyServer.BeforeRequest += OnRequest;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);
proxyServer.AddEndPoint(explicitEndPoint);
proxyServer.Start();
foreach (var endPoint in proxyServer.ProxyEndPoints)
_logger.LogInformation("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
// Console.ReadLine();
stoppingToken.Register(() =>
{
proxyServer.BeforeRequest -= OnRequest;
proxyServer.Stop();
});
await Task.Delay(Timeout.Infinite, stoppingToken);
}
catch (Exception)
{
throw;
}
});
private async Task OnRequest(object sender, SessionEventArgs e)
{
var filePath = #"E:\LogiusService\Logs\log.txt";
Log.Logger = new LoggerConfiguration()
.WriteTo.File(filePath, rollingInterval: RollingInterval.Day, shared: true)
.CreateLogger();
string requestedUrl = e.HttpClient.Request.Host;
Console.WriteLine("Requested URL: " + requestedUrl);
Log.Information($"Requested URL: " + requestedUrl);
string requestedUri = e.HttpClient.Request.RequestUri.AbsoluteUri;
Console.WriteLine("Requested URI: " + requestedUri);
Log.Information($"Requested URI: " + requestedUri);
}
}
}
Any ideas how can i run it as Windows Background Service?
Cheers!

No handlers for address while using eventBus in communicating between verticles of a springboot project

I developed a project with Springboot and used Vertx as an asynchronous reactive toolkit. My ServerVerticle, create a httpServer which receives http requests from an Angular app and sends messages to it via eventBus. By the way, the time that received message arrives, ServerVerticle sends it to another verticle which has service instance in it (for connecting to repository). i tested it with postman and get "No handlers for address" error as a bad request.
here is my ServerVerticle:
HttpServerResponse res = routingContext.response();
res.setChunked(true);
EventBus eventBus = vertx.eventBus();
eventBus.request(InstrumentsServiceVerticle.FETCH_INSTRUMENTS_ADDRESS, "", result -> {
if (result.succeeded()) {
res.setStatusCode(200).write((Buffer) result.result().body()).end();
} else {
res.setStatusCode(400).write(result.cause().toString()).end();
}
});
My instrumentVerticle is as follows:
static final String FETCH_INSTRUMENTS_ADDRESS = "fetch.instruments.service";
// Reuse the Vert.x Mapper :)
private final ObjectMapper mapper = Json.mapper;
private final InstrumentService instrumentService;
public InstrumentsServiceVerticle(InstrumentService instrumentService) {
this.instrumentService = instrumentService;
}
private Handler<Message<String>> fetchInstrumentsHandler() {
return msg -> vertx.<String>executeBlocking(future -> {
try {
future.complete(mapper.writeValueAsString(instrumentService.getInstruments()));
} catch (JsonProcessingException e) {
logger.error("Failed to serialize result "+ InstrumentsServiceVerticle.class.getName());
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
msg.reply(result.result());
} else {
msg.reply(result.cause().toString());
}
});
}
#Override
public void start() throws Exception {
super.start();
vertx.eventBus().<String>consumer(FETCH_INSTRUMENTS_ADDRESS).handler(fetchInstrumentsHandler());
}
and i deployed both verticles in the springbootApp starter.

Problems with deploying Service Fabric project with Owin to Azure Service Fabric Cluster

I am working on a Service Fabric project with Owin, and I'm having troubles getting it deployed into the cloud. I have searched for others with the same problem, but I only found an answer telling that the error in the cluster tells where in the code it goes wrong. I have followed Microsofts Owin tutorial on how to write the method that fails, but with no luck.
I can run the project on Localhost direcly from Visual Studio, but the problem starts when I deploy it to a Service Fabric cluster in Azure. I have a 5 node cluster running, and when I deploy to it, it starts giving warnings after 2 minutes, and errors after 5 minutes. the status of the application is "inbuild".
Image of warning and Image of error.
I have two services, and the error from my cluster gives the error in these two methods(the same method in each service(OpenAsync)):
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var serviceEndpoint =
_parameters
.CodePackageActivationContext
.GetEndpoint("ServiceEndpoint");
var port = serviceEndpoint.Port;
var root =
String.IsNullOrWhiteSpace(_appRoot)
? String.Empty
: _appRoot.TrimEnd('/') + '/';
_listeningAddress = String.Format(
CultureInfo.InvariantCulture,
"http://+:{0}/{1}",
port,
root
);
_serverHandle = WebApp.Start(
_listeningAddress,
appBuilder => _startup.Configuration(appBuilder)
);
var publishAddress = _listeningAddress.Replace(
"+",
FabricRuntime.GetNodeContext().IPAddressOrFQDN
);
ServiceEventSource.Current.Message("Listening on {0}", publishAddress);
return Task.FromResult(publishAddress);
}
the error from the cluster tells the error is in this section:
_serverHandle = WebApp.Start(
_listeningAddress,
appBuilder => _startup.Configuration(appBuilder)
);
the other method(from the other service):
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
var serviceEndpoint =
_parameters
.CodePackageActivationContext
.GetEndpoint("ServiceEndpoint");
var port = serviceEndpoint.Port;
var root =
String.IsNullOrWhiteSpace(_appRoot)
? String.Empty
: _appRoot.TrimEnd('/') + '/';
_listeningAddress = String.Format(
CultureInfo.InvariantCulture,
"http://+:{0}/{1}",
port,
root
);
try
{
_serverHandle = WebApp.Start(
_listeningAddress,
appBuilder => _startup.Configuration(appBuilder)
);
}
catch (Exception e)
{
Console.WriteLine(e);
throw e;
}
var publishAddress = _listeningAddress.Replace(
"+",
FabricRuntime.GetNodeContext().IPAddressOrFQDN
);
ServiceEventSource.Current.Message("Listening on {0}", publishAddress);
return Task.FromResult(publishAddress);
}
the error from the cluster tells the error is in this section:
try
{
_serverHandle = WebApp.Start(
_listeningAddress,
appBuilder => _startup.Configuration(appBuilder)
);
}
catch (Exception e)
{
Console.WriteLine(e);
throw e;
}
My StartUp Classes:
public void Configuration(IAppBuilder appBuilder)
{
var corsAttr = new EnableCorsAttribute(origins: "*", headers: "*", methods: "*");
var config = new HttpConfiguration();
config.WithWindsorSetup();
config.WithJsonSetup();
config.MapHttpAttributeRoutes(); //Enable Attribute-routing
config.WithSwaggerSetup();
config.EnsureInitialized();
config.EnableCors(corsAttr);
appBuilder.UseWebApi(config);
}
and where I create a new OwenCommunicationListener:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] {
new ServiceInstanceListener(initParams => new OwinCommunicationListener("", new Startup.Startup(), initParams))
};
}
I would very much like to be able to deploy it to Azure Service Fabric Cluster without any errors. Have a nice day, and thanks for helping.
you need to write your own custom class that configure the routing and http configuration for Owin listener.
Here is the class which I am using to configure the routing, try with it:
/// <summary>
/// This is the startup class that configure the routing and http configuration for Owin listener.
/// </summary>
public static class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public static void ConfigureApp (IAppBuilder appBuilder)
{
appBuilder.UseCors(CorsOptions.AllowAll);
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
config.Formatters.Remove(config.Formatters.XmlFormatter);
appBuilder.UseWebApi(config);
}
}
pass this class as an action to instance where you are creating instance of OwinCommunication Listener. Here is my code
endpoints.Select(endpoint => new ServiceInstanceListener(
serviceContext => new OwinCommunicationListener(Startup.ConfigureApp, serviceContext,
null, endpoint), endpoint));
This approach is working for me. Try with it hopefully it will work for you too
problem is solved. I edited this code:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return Context.CodePackageActivationContext.GetEndpoints()
.Where(endpoint => endpoint.Protocol.Equals(EndpointProtocol.Http) || endpoint.Protocol.Equals(EndpointProtocol.Https))
.Select(endpoint => new ServiceInstanceListener(serviceContext => new OwinCommunicationListener("", new Startup.Startup(), serviceContext)));
//return new[] {
// new ServiceInstanceListener(initParams => new OwinCommunicationListener("", new Startup.Startup(), initParams))
//};
}

Display available REST resources in development stage

I was wondering wheather it's possible to output the available REST paths of a Java EE web app (war deplopyment) as a summary on a page. Of course, for security reasons only in development mode. Is there something available for this?
Thanks
Here is a quick + dirty example which will return all paths for the scanned ResourceClasses:
Path("/paths")
public class PathResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response paths(#Context HttpServletRequest request) {
StringBuilder out = new StringBuilder();
String applicationPath = "/"; // the path your Application is mapped to
#SuppressWarnings("unchecked")
Map<String, ResteasyDeployment> deployments = (Map<String, ResteasyDeployment>) request.getServletContext().getAttribute("resteasy.deployments");
ResteasyDeployment deployment = deployments.get(applicationPath);
List<String> scannedResourceClasses = deployment.getScannedResourceClasses();
try {
for (String className : scannedResourceClasses) {
Class<?> clazz = Class.forName(className);
String basePath = "";
if (clazz.isAnnotationPresent(Path.class)) {
basePath = clazz.getAnnotation(Path.class).value();
}
out.append(String.format("BasePath for Resource '%s': '%s'", className, basePath)).append('\n');
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Path.class)) {
String path = method.getAnnotation(Path.class).value();
out.append(String.format("Path for Method '%s': '%s'", method.getName(), basePath + path)).append('\n');
}
}
}
} catch(ClassNotFoundException ex) {
throw new IllegalArgumentException(ex);
}
return Response.ok(out).build();
}
}
For developers who are working with Eclipse. Simply use open the Project Exlorer view and see the list of available resources under JAX-RS Web Services. I'm positive there is something similar for other IDEs.

Value lost when transferring from server to client in silverlight

I am making a Silverlight app using WCF. I want to get the status of the hard-disks from remote servers and I am able to do that on the server side using a Management object. I have defined a wrapper class to hold the data of the hard-disks and store the objects in a list which I return.
Earlier, when the wrapper class was in the server project, it worked fine. However, when I transferred the class to a class library project in the same solution, the asynchronous call-completed event handler on the client side now gives me an event argument that is empty, i.e. an empty list
I tried debugging both the server and client code, and I see that the server creates the list properly and accesses the disk objects nicely. But the client code simply shows the list to be of size 0.
My client code is:
private void getDiskStatus()
{
diskSpaceStatus.Text = "Running...";
if (server == string.Empty)
{
server = "localhost";
}
diskServer.Text = server;
LogReaderClient proxy = new LogReaderClient();
proxy.getDiskSpaceCompleted += new EventHandler<getDiskSpaceCompletedEventArgs>(proxy_getDiskSpaceCompleted);
proxy.getDiskSpaceAsync(server);
}
void proxy_getDiskSpaceCompleted(object sender, getDiskSpaceCompletedEventArgs e)
{
diskSpaceStatus.Text = "Completed";
try
{
List<uDisk> udisks = new List<uDisk>();
foreach (Disk d in e.Result)
{
uDisk ud = new uDisk(d);
udisks.Add(ud);
}
diskTable.ItemsSource = udisks;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Where uDisk is another wrapper class for the client side.
My server code is:
[OperationContract]
public List<Disk> getDiskSpace(string server)
{
ConnectionOptions conn = new ConnectionOptions();
ManagementScope scope = new ManagementScope("\\\\" + server + "\\root\\cimv2", conn);
try
{
scope.Connect();
}
catch (Exception ex)
{
error = ex.Message;
}
ObjectQuery oq = new ObjectQuery("select FreeSpace, Size, Name from Win32_LogicalDisk where DriveType=3");
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, oq);
ManagementObjectCollection moc = search.Get();
List<Disk> disks = new List<Disk>();
Disk d;
foreach (ManagementObject mo in moc)
{
d = new Disk(mo);
disks.Add(d);
}
return disks;
}
And the server wrapper class is:
namespace LogFilter.DataObjects
{
[DataContract]
public class Disk
{
[DataMember]
public string name;
[DataMember]
public double freeSpace;
[DataMember]
public double size;
[DataMember]
public double percentFree;
public Disk()
{}
public Disk(ManagementObject mo)
{
this.name = Convert.ToString(mo["Name"]);
this.freeSpace = Convert.ToDouble(mo["FreeSpace"]);
this.size = Convert.ToDouble(mo["Size"]);
this.percentFree = freeSpace * 100 / size;
}
}
}
The wrapper class is in the namespace LogFilter.DataObjects and the Server code is in the namespace LogFilter.Web.
Can anyone provide a solution to this?
Also can someone please give me a resource as to how to set the transfermode in a Silverlight application to Buffered?