Can't start a WCF Service installed as a Windows Service - web-services

I created a service that basically exposes some methods to update a sql server database.
I tested the service as a normal WCF Service (not a Windows Service) and it worked fine (which tells me that the ServiceModel definition in App.config is ok)
Then I turned it into a Windows Service, I installed it using InstallUtil, and it installed fine. But when trying to start it in the Services console, I get this message "The service WCFProductsWindowsService service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs"
The solution that exposes the service is composed of two projects,
a class library that defines the service, the contract, and an ADO
NET Entity Data Model to the database,
and a console application that exposes the service
The class that exposes the serice is:
public class ProductsWindowsService : ServiceBase {
public ServiceHost serviceHost = null;
public ProductsWindowsService() {
ServiceName = "WCFProductsWindowsService";
}
public static void Main() {
ServiceBase.Run(new ProductsWindowsService());
}
protected override void OnStart(string[] args) {
if (serviceHost != null) {
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(ProductsServiceImpl));
serviceHost.Open();
}
protected override void OnStop() {
if (serviceHost != null) {
serviceHost.Close();
serviceHost = null;
}
}
}
I uploaded the simple project in SkyDrive
What could I be doing wrong?

Does not allow me to add a comment.
This error "The service WCFProductsWindowsService service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs" indicates an exception is thrown.
I would check the event viewer to see the exception logged.
Does ProductsServiceImpl exists? I can't find it in your image or in your solution.

Related

Get Azure WebJobs connection strings from KeyVault before host is built

I am following the directions at https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references
Essentially, I am attempting to protect the storage connection string used for AzureWebJobsDashboard and AzureWebJobsStorage behind an Azure Key vault secret. I cannot use my injected KeyVault service to fetch it because my service container has not been built yet. So I found (through the link above) I could express this intent using a "#Microsoft.KeyVault()" expression in configuration. Here is an example where I moved the configuration to inline code to keep it terse:
.ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder
.AddConfiguration(configuration)
.AddInMemoryCollection(new Dictionary<string, string>
{
["ConnectionStrings:AzureWebJobsDashboard"] = "#Microsoft.KeyVault(SecretUri=https://host.vault.azure.net/secrets/secret-name/ec545689445a40b199c0e0a956f16fca)",
["ConnectionStrings:AzureWebJobsStorage"] = "#Microsoft.KeyVault(SecretUri=https://host.vault.azure.net/secrets/secret-name/ec545689445a40b199c0e0a956f16fca)",
});
})
If I run this, I get:
FormatException: No valid combination of account information found.
If I change the configuration values from the special annotation to the copied secret value from Key Vault (the blue copy button under the 'Show Secret Value' button), everything just works. This confirms to me the connection string I use is correct.
Also, I manually used KeyVaultClient w/AzureServiceTokenProvider to verify the process should work when running locally in Visual Studio, even before the host has been built. I am able to get the secret just fine. This tells me I have sufficient privileges to get the secret.
So now I am left wondering if this is even supported. There are pages which imply this is possible however, such as https://medium.com/statuscode/getting-key-vault-secrets-in-azure-functions-37620fd20a0b. At least for Azure Functions. I am using Azure Web Jobs which gets deployed as a console application with an ASP.NET Core service, and I cannot find an example with that configuration.
Can anybody clarify if what I am doing is supported? And if not, what is the advisable process for getting connection strings stored in Azure Key Vault before the Azure Web Jobs host has been built?
Thanks
I have gone through a lot of online resources and everything seems to indicate that the special decorated #Microsoft.KeyVault setting only works when the value lives in AppSettings on the Azure Portal, not in local configuration. Somebody please let me know if that is an incorrect assessment.
So to solve this problem, I came up with a solution which in all honesty, feels a little hacky because I am depending on the fact that the connection string is not read/cached from local configuration until the host is ran (not during build). Basically, the idea is to build a configuration provider for which I can set a value after the host has been built. For example:
public class DelayedConfigurationSource : IConfigurationSource
{
private IConfigurationProvider Provider { get; } = new DelayedConfigurationProvider();
public IConfigurationProvider Build(IConfigurationBuilder builder) => Provider;
public void Set(string key, string value) => Provider.Set(key, value);
private class DelayedConfigurationProvider : ConfigurationProvider
{
public override void Set(string key, string value)
{
base.Set(key, value);
OnReload();
}
}
}
A reference to this type gets added during host builder construction:
var delayedConfigurationSource = new DelayedConfigurationSource();
var hostBuilder = new HostBuilder()
.ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder
.AddConfiguration(configuration)
.Add(delayedConfigurationSource);
})
...
And just make sure to set the configuration before running the host:
var host = hostBuilder.Build();
using (host)
{
var secretProvider = host.Services.GetRequiredService<ISecretProvider>();
var secret = await secretProvider.YourCodeToGetSecretAsync().ConfigureAwait(false);
delayedConfigurationSource.Set("ConnectionStrings:AzureWebJobsStorage", secret.Value);
await host.RunAsync().ConfigureAwait(false);
}
If there is a more intuitive way to accomplish this, please let me know. If not, the connection string design is plain silly.

How to dynamically call the webservices from .NET Core

Currently I am consuming some webservices with multiple endpoints in .NET with the help of WCF Webservices reference provider tool. If there are any changes in webservices then I have to update or delete and reattach, then again will have to build to get the DLL and put in to deployment server.
This is very time consuming. Are there any alternate options?
At first, the WCF created by some complex bindings, authentication security may not work well with NetCore,such as Wshttpbinding. Generally, basichttpbinding is supported by the Core-based client.
With the interface, address and other service information unchanged, we can call the service dynamically through the channel factory, No matter how the server changes the implementation of the service. It does not affect the client’s invocation.
Here is an example.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://10.157.13.69:1500");
BasicHttpBinding binding = new BasicHttpBinding();
ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(binding,new EndpointAddress(uri));
ICalculator service = factory.CreateChannel();
try
{
var result = service.Add(34.32, 2.34);
Console.WriteLine(result);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
}
}
[ServiceContract]
public interface ICalculator
{
[OperationContract]
double Add(double a, double b);
}
Here is a related document.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-channelfactory
Feel free to let me know if there is anything I can help with.

How to receive the returned result of window service if the window service has started programmatically from web service

I have window service within a web service. I started the window service from the web service programmatically. My problem is how to receive the result of that window service in web service.code for starting the window service is
ServiceController[] services = ServiceController.GetServices();
ServiceController service = null;
foreach (ServiceController Item in services)
{
if (Item.DisplayName == "Service1")
{
service = new ServiceController("Service1");
TimeSpan timeout = TimeSpan.FromHours(24);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
break;
}
}
This service will call function Execute() and that will return a string after execution.How Can i receive that string in web service
Short answer
You can't.
Long answer
The windows services started in this manner are running in app domains which are completely isolated from the one the web service is running in. They are also isolated from each other.
In order to know the internal state of these windows services, you either need to have them implement some kind of remoting mechanism (like a web service) or have the service write to some physical resource such as a file or database.

Application Failed to Initialize Properly (0xc0000142)

I'm trying to launch notepad.exe(as a simpler test) from a web service using process.Start(). This web service is deployed to IIS 5.1 on Windows XP (for development) and will likely be deployed to a Windows 2003 server with IIS 6. This is the code that I am using:
[WebMethod]
public String ReqFormImage(String qString)
{
_qString = qString;
String imageLoc = #"http://localhost/MobileService/formImages/" + NameOfScreenshot(qString);
Process myProcess = new Process();
try
{
//Credentials
myProcess.StartInfo.Domain = "domain";
myProcess.StartInfo.UserName = "myUserName"; //local admin on development pc
myProcess.StartInfo.Password = PasswordGenerate("removed");
//StartInfo
myProcess.StartInfo.WorkingDirectory = #"C:\WINDOWS\System32";
myProcess.StartInfo.FileName = "notepad.exe";
//myProcess.StartInfo.Arguments = qString;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
//myProcess.StartInfo.LoadUserProfile = false;
myProcess.Start();
myProcess.WaitForExit();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return imageLoc;
}
I also have impersonate set to true in the web.config (I've tried with and without my credentials in the config file, as well as with impersonate set to false). I've also given read/execute permission to my user ID, aspnet, and the service account on notepad.exe.
A breakpoint on myProcess.WaitForExit() causes a message box to pop up that says, "Application Failed to Initialize Properly (0xc0000142)." I looked at the event log and there is no further information than this.
What I need in the end is to be able to launch an exe impersonating an account that can be hardcoded or impersonating the user that accesses the web service. I know that there are issues with opening an exe with a GUI server-side, but I need this to work. I'm sure this isn't the best practice, but I am running short on time and am looking for a workaround. For now, at least getting notepad to launch will be sufficient.
Thanks for any help.
In IIS I had to set the web service to run scripts and executables, not just scripts. Notepad launches now, but without a full GUI. I don't think what I need is possible, but I solved what I asked.

Consuming services that consume other services

What is the best way to confirm that these consumed services are actually up and running before I actually try to invoke its operation contracts? I want to do this so that I can gracefully display some message to the customer to give him/her a more pleasant user experience. Thanks.
I created an IsAvailable method that checked all of my underlying dependencies for my service. My client would call this method before doing anything else with my service. If it returned true, my service was available for use.
We also put intermediaten checks to rollback any changes if one of the underlying dependencies was not able at the time of the transaction.
Example:
Here is a simple example of how my IsAvailable is used by the client:
IsAvailable code
[WebMethod]
public bool IsAvailable()
{
bool EverythingUpAndRunning = true;
try
{
string TestConnectionString = WebConfigurationManager.ConnectionStrings["Sql"].ConnectionString;
SqlConnection sqlConnection = new SqlConnection(TestConnectionString);
sqlConnection.Open();
sqlConnection.Close();
sqlConnection.Dispose();
}
catch(Exception ex)
{
EverythingUpAndRunning = false;
}
return EverythingUpAndRunning;
}
The client code:
MyWebService proxy = new MyWebService();
if(proxy.IsAvailable)
{
//if true, you can use the other available methods in the service
}
I wouldn't consider myself a part of the SO Community but I have been in this situation before and it was simple exception handling around the service calls. If you're in control of the services, than you can put up a status method that returns it's current state. If the network is down and you can't even hit the service than you'll have to handle that with some exception handling but you could get a status back if the parent service is unable to use it's child services.
If you're following SO though, my own opinion here, you shouldn't be concerned with the consumed service consuming other services.