I've hunted for the answer to this one, in SO and beyond but I've not seen any answers thus far.
We are looking at adding some reporting to an existing Windows Services / WPF EXE. Ideally we'd self-host a little vNext application that would expose reporting endpoints our app can use. This was possible with OWIN and ASP.NET 4.
Is this even possible with vNext?
I've tried a few samples etc and the K Runtime seems to, clearly, be a different runtime to the CLR. Build etc is all rather different too... so I guess at the very least it would have to be a completely separate process .... or am I barking up the wrong tree?
In particular it seems we need to invoke the K runtime (k web or elsed a k pack'ed .cmd) which seems coutner intuitive as I'm already within a process I'm running (the main exe/service).
EDIT: I'm wondering if the answer is NoWin , referenced and providing the OWIN container. B ut I'm struggling to see if that's the best approach...
Here a possible solution: How to Run DNX Applications in a Windows Service and
How to Host ASP.NET in a Windows Service thanks to Erez Testiler.
Basically the idea is to add the following references:
"Microsoft.AspNet.Hosting": "1.0.0-beta7" – Bootstraps the web server
"Microsoft.AspNet.Server.Kestrel": "1.0.0-beta7" – Web server implementation
"Microsoft.AspNet.StaticFiles": "1.0.0-beta7" – Hosts static files
"Microsoft.AspNet.Mvc": "6.0.0-beta7" – Includes all the MVC packages
And then programmatically configure and start the Server and ASP.NET:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Internal;
using Microsoft.Framework.Configuration;
using Microsoft.Framework.Configuration.Memory;
using Microsoft.Framework.DependencyInjection;
using System;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
....
private readonly IServiceProvider _serviceProvider;
private IHostingEngine _hostingEngine;
private IDisposable _shutdownServerDisposable;
public Program(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override void OnStart(string[] args)
{
var configSource = new MemoryConfigurationSource();
configSource.Add("server.urls", "http://localhost:5000");
var config = new ConfigurationBuilder(configSource).Build();
var builder = new WebHostBuilder(_serviceProvider, config);
builder.UseServer("Microsoft.AspNet.Server.Kestrel");
builder.UseServices(services => services.AddMvc());
builder.UseStartup(appBuilder =>
{
appBuilder.UseDefaultFiles();
appBuilder.UseStaticFiles();
appBuilder.UseMvc();
});
_hostingEngine = builder.Build();
_shutdownServerDisposable = _hostingEngine.Start();
}
It seems to be a quite good solution to me.
Ok I spent some time on jabbr.net and had some help from the awesome #dfowl and a helpful if rather curt younger dev (those were the days).
#dfowl: that scenario Is pretty much dead
My take- as our Windows Service/WPF runs under CLR and vNext runs under CLR they are different runtimes.
There is a way to do it, based on an older version of the K runtime and it's er, hairy. File in possible, but never something you'd put in production:
Alxandr's CLR Bootstrap for K runtime
Related
I am building an windows service that manages several tasks in the background. To manage these tasks and see progress and status I thought it should be possible to add some kind of webapi that exposes the service its state and allows for starting, stopping and submitting tasks.
But though I can find many sites telling me how to host an asp.net core application as a (windows) service. I can't seem to google the correct information that tells me the correct way to bolt a webservice to an existing application. The difference being that the web-interface would be one of several interfaces into and not the primary base of the application (i.e. I'm not looking for backgroundtasks inside a webapp). Thus the webhost will function as a "plugin" from the applications point of view.
If anyone knows of a proper example or has some pointers for me?
Attempt a explanatory image:
In yellow the host application, in green the parts I already have. In red the thing I'm asking about. The red and green things are basically plugins.
Update2:
I'm using DotNetCorePlugins framework for my plugins. As a test I created an mvc webapi project (net5). Changed the application type from console to class library and changed the code in program to this:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using PluginTester.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace PluginTester.Plugin3
{
public class Plugin3 : IPlugin
{
IHostBuilder builder;
public string GetName()
{
return "Web API Service";
}
public void Start()
{
CreateHostBuilder(new string[0]).Build().Run();
}
public void Stop()
{
//builder.
}
public IHostBuilder CreateHostBuilder(string[] args) =>
builder = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
//public static void Main(string[] args)
//{
// //CreateHostBuilder(args).Build().Run();
// new Plugin3().Start();
//}
}
}
This is my "tech-test" application do excuse the naming. The start function is called when the plugin is loaded. This basically works and I can call the default weatherforecast service. The Swagger stuff for some reason does not work, but that is for later.
I had to add some assembly resolve code to the host application borrowed from here: assembly resolving for addins. As my plugins are in subfolders of the bin folder.
Open questions
Is this the correct way to start the webhost?
How do I communicate from the mvc controllers with the host applications to retrieve internal status from other plugins?
how do I stop de webhost?
My team recently inherited an ASP.NET solution that runs on Azure App Services. One project in the solution seems to define C# code that leverages the Azure WebJobs SDK to run several functions. I am not a C# or ASP.NET developer by trade, but I'm involved in developing the build and release pipelines for the project.
I have two App Service environments that need to run the WebJobs project, but in the case of one of those environments, some of the functions should not run.
Each function seems to have its own .cs file, and it seems these functions can inherit configuration from an App.config file (which can be transformed at runtime using files like App.Staging.config and App.Prod.config). An example of a function in the project might look like:
using Microsoft.Azure.WebJobs;
using System;
using System.Configuration;
using System.IO;
namespace My.Project.WebJobs
{
public class SomeTask
{
public void ExecuteTask([TimerTrigger(typeof(CustomScheduleDaily3AM))]TimerInfo timerInfo, TextWriter log)
{
var unitOfWork = new UnitOfWork();
var SomeSetting = int.Parse(ConfigurationManager.AppSettings["SomeSetting"]);
unitOfWork.Execute.Something();
}
}
}
With my limited understanding of my options, the first idea that occurred to me was to potentially add an enable/disable switch to the method(s) (i.e. SomeTask or ExecuteTask in the example above) that might read its true/false value from a setting defined in App.config. Though, not being well-versed in C#... I'm not confident this is possible. Doing it this way, the function may still run, but no action is taken on account of the method(s) being disabled.
I feel as if there may be a solution that relies more on Azure configuration as opposed to function-level code changes. Any help is appreciated.
After researching, I found three ways to meet your need.
Create multiple instance depends on different environment, and publish your WebJobs to different instance.
Use staging slots.
Use 'ASPNETCORE_ENVIRONMENT' appsettings. I would show how below:
Configure the ASPNETCORE_ENVIRONMENT on portal. (This setting was in launchSettings.json file in local machine)
Modify your code like this (just for showing how it works, more info see the doc):
if (_env.IsDevelopment())
{
Console.WriteLine(_env.EnvironmentName); //modify with your function
}
else if (_env.IsStaging())
{
Console.WriteLine(_env.EnvironmentName); //modify with your function
}
else
{
Console.WriteLine("Not dev or staging"); //modify with your function
}
Here is a reference about Use multiple Environments in ASPNET CORE,
I am looking for an example for a simple webjob:
the task would be to process the response from a web link and save it to blob on a regular time interval.
first of all the ms documentation is confusing me as far as time triggers are concerned:
https://learn.microsoft.com/en-us/azure/app-service/webjobs-create#ncrontab-expressions
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=csharp#example
and also how exactly should I proceed on building the WebJob, should I use an azure webjob template (.net 4.x.x), or .net core console app ??
https://learn.microsoft.com/en-us/azure/app-service/webjobs-sdk-how-to
https://github.com/Azure/azure-webjobs-sdk-samples/tree/master/BasicSamples
https://learn.microsoft.com/en-us/azure/app-service/webjobs-sdk-get-started
https://learn.microsoft.com/en-us/azure/app-service/webjobs-create
all this resource and no simple example for a time scheduled task that would get a web response, also the confusion on building the webjob VS, wth?? I want to build a c# app in VS and deploy to azure as webjob via azure devops.
wasted 3 days on this since im not a .net developer...
Webjobs have changed and grown over the years including contributions from Azure Functions, which is also built on top of the Webjobs SDK. I can see how this can get confusing, but the short answer is that all of the different methods are still valid, but some are newer than others. Of the two timer trigger styles, the second is more current.
I generally recommend Functions instead of Webjobs for something like this since at this point as it will save you some boiler-plate code, but it is entirely up to you. As I mentioned, the foundations are very similar. You can deploy Functions apps to any App Service plan, including the Consumption plan- this is specific to Functions that is pay-by-usage instead of a monthly fee like you would need for WebJobs.
As far as .NET Framework vs. .NET Core, you can use it will depend on what runtime you used to set up your App Service. If you have a choice, I would recommend using Core since that will be the only version moving forward. If you elect to use Functions, you will definitely want to use Core.
As far as the Console App question, all WebJobs are essentially console apps. From a code perspective, they are a console app that implements the Webjobs SDK. You could run them outside of Azure if you wanted to. Functions apps are different. The Function's host is what actually runs behind the scenes and you are creating a class library that the host consumes.
Visual Studio vs. Visual Studio Code is very much a personal preference. I prefer VS for Webjobs and work with both VS and VS Code for Functions apps depending on which language I am working in.
The most basic version of a Webjob in .NET Core that pulls data from a webpage on a schedule and outputs it to blob storage would look something like this. A Function app would use exactly the same GetWebsiteData() method plus a [FunctionName("GetWebsiteData")] at the beginning, but you wouldn't need the Main method as that part is handled by the host process.
public class Program
{
static async Task Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
b.AddTimers();
});
builder.ConfigureAppConfiguration((context, configurationBuilder) =>
{
configurationBuilder
.AddJsonFile($"appsettings.json", optional: true);
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
public async static void GetWebsiteData(
[TimerTrigger("0 */1 * * * *")] TimerInfo timerInfo,
[Blob("data/websiteData", FileAccess.Write)] Stream outputBlob,
ILogger logger)
{
using(var client = new HttpClient())
{
var url = "https://microsoft.com";
var result = await client.GetAsync(url);
//you may need to do some additional work here to get the output format you want
outputBlob = await result.Content.ReadAsStreamAsync();
}
}
}
I have been trying to get a WCF Data Service server working for a few days now.
I finally backed off today and just tried to do exactly what the quick-start shows.. nothing else.. and in completely fresh project. Surely that would work.
But it didn't.. it failed the same way as my other tests.
I am just following along with this example. Using Visual Studio 2013 for Web express and the hosting is using IIS Express.
I have installed the WCF Tools version 5.6 such that Visual Studio has the WFC Data Service 5.6 template.
The gist of it is
create an ASP.Net Application Select MVC type, adding no folders for anything other than MVC and no unit tests, individual account authenticaion.
Add an ADO.Net Entity Data Model for the NorthWind database, called NorthwindEntities in web.config, importing all tables.
Add WCF Data Service 5.6 item, call it NorthWind.svc.
Change the NorthWind.svc.cs backing code to the following.
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
namespace StackOverflowApp
{
public class NorthWindService : DataService<NorthwindEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.UseVerboseErrors = true;
config.SetEntitySetAccessRule("Orders", EntitySetRights.AllRead | EntitySetRights.WriteMerge | EntitySetRights.WriteReplace );
config.SetEntitySetAccessRule("Order_Details", EntitySetRights.AllRead| EntitySetRights.AllWrite);
config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
}
Now it is ready to build and run.. it should work.. yes?
I run it, and navigate to the service.. I am greeted with the following complaint.
<div id="content">
<p class="heading1">Request Error</p>
<p>The server encountered an error processing the request. See server logs for more details.</p>
</div>
How am I to debug that?
This is not the typical response when navigating to a page which generates an error in the application or to a page that does not exist. I get the feeling that the data.service system is generating this response.. that it actually started to process the request.. but failed for some obtuse reason.
I followed the instructions to a tee I thought, but apparently I missed something.
I've been through the process step by step several times now to try to find what I might have skipped to no avail.
Update:
Aha.. under another similar question, they recommended adding verbose messages using config.UserVerboseErrors = true. This didn't make any difference to me.. but the alternative method of using attributes sure did! Decorating the class with [ServiceBehavior(IncludeExceptionDetailInFaults = true)], now yields this more descriptive error.
The server encountered an error processing the request. The exception
message is 'Expression of type
'System.Data.Entity.Core.Objects.ObjectContext' cannot be used for
return type 'System.Data.Objects.ObjectContext''. See server logs for
more details. The exception stack trace is: blahblah
It sounds like you're using Entity Framework 6 which hasn't been out for all that long. You need to perform some additional steps to get WCF Data Services 5.6 and EF 6 to behave together nicely.
You need to add the additional WCF Data Services Entity Framework Provider Nuget package and then instead of inheriting your service from DataService<T>, you inherit from EntityFrameworkDataService<T>.
Full steps are on the data services blog here: http://blogs.msdn.com/b/astoriateam/archive/2013/10/02/using-wcf-data-services-5-6-0-with-entity-framework-6.aspx
Yes Thanks. Your answer is correct Chris. I was able to find the problem at last after I enabled the decorated version of verbose messaging, and got that extra detail regarding linking to objects being the problem.
So I found the problem and fixed it, or at least I can make it work using the quick-start guide now. Working with my own database is a little squirley still.. returns an empty set when I know I have items in the database.. but at least I now have working exhibit-A to compare against to find the issue. (Aha! found the problem there also, I had forgotten to add the entitie connection to web.config for my non-northwind database -- so its all workin' now!)
Anyway, the first decent clue was following the error message (that wasn't shown until after I enabled verbose messaging with the class attribute), found this note about the problem actually being with WCF's interface with EntityFramework 6. (had I not upgraded to version 6 I likely would not have had the problem)
https://entityframework.codeplex.com/workitem/896
Then, I searched for issues with WCF 5.6 and EntityFramework6. and whalla.. there is an alpha version of WCF which addresses the issue.
Note that if you follow the instructions here verbatim, there is still a problem (or was for me). Get alpha2 instead of alpha1 as it fixes a linking error. i.e.
Install-Package Microsoft.OData.EntityFrameworkProvider -Version 1.0.0-alpha2 -Pre
http://blogs.msdn.com/b/astoriateam/archive/2013/10/02/using-wcf-data-services-5-6-0-with-entity-framework-6.aspx
To install alpha2 today 6/7/2014 "Install-Package Microsoft.OData.EntityFrameworkProvider -Pre". Also the Microsoft.Data.Services version must be 5.6.0.0.
I'm writing a service monitoring ASP .NET app and I'm having issues particularly with getting the service descriptions. My current method (reading from registry) is not going to work due to registry read permissions on the production server.
For example:
Microsoft.Win32.RegistryKey system, currentControlSet, services, service;
system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System");
currentControlSet = system.OpenSubKey("CurrentControlSet");
services = currentControlSet.OpenSubKey("Services");
service = services.OpenSubKey(scTemp.ServiceName, true);
row["service_description"] = service.GetValue("Description");
Produces:
System.Security.SecurityException: Requested registry access is not allowed.
My question is:
Is there a work-around with another .NET class (maybe under System.ServiceProcess namespace?) or will it always end with a security exception error?
I have no issues getting Service names and states with the System.ServiceProcess namespace but I can't find any classes contained to get descriptions which is why I resorted to reading from registry.
I think this should work.
EDIT: I should read questions closer. The code below gets the description for the first service in the array.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Management;
namespace ServiceNames
{
class Program
{
static void Main(string[] args)
{
ServiceController[] services = ServiceController.GetServices();
string serviceName = services[0].ServiceName;
string objPath = string.Format("Win32_Service.Name='{0}'", serviceName);
using (ManagementObject service = new ManagementObject(new ManagementPath(objPath)))
{
Console.WriteLine(service["Description"]);
}
Console.Read();
}
}
}
The previous answer showing the WMI solution is a good alternative and worth trying first.
--
I am not aware of a .NET Framework class that exposes the service description.
The first thing I would consider is requiring authenticated connections (e.g. NTLM) and impersonate the caller. As long as you don't do a double-hop (i.e. make a remote call with your impersonated credentials) you may find that you are able to successfully make the registery read.
If that is not possible then making a P/Invoke call may work.
If the credentials your web service has the SERVICE_QUERY_CONFIG permission you could do the following:
Find the service you are interested in using the ServiceController class
Using the ServiceHandle property make a P/Invoke call to QueryServiceConfig2 using the SERVICE_CONFIG_DESCRIPTION info level passing in null for the buffer and 0 for the lenght, reading the required buffer length from pcbBytesNeeded.
Allocate the proper buffer length and call QueryServiceConfig2 a second time getting the service description.
Obviously reading from the registery is a little more straight-forward (and in the end the permissions issues may be similar in both cases) - but using a supported API seems like a less fragile solution.
Side question: is there something you are trying to accomplish that PerfMon and logging can't tell you?