I have a C# solution with multiple projects in it.
There is one project called Console which run as a service and this project has a reference to the hostSoftware project (hostSoftware doesn't have a reference to Console, obviously).
I want to transfer a bool value from Console to hostSoftware.
Console: Checks the license and I want to send the bool value to hostSoftware for further checks.
var StatusParameters1 = new StatusParameters();
{
StatusParameters1.Name = "Log";
int returnCode = 0;
bool logStatus = LHandler.GetLogStatus(out LogStatus);
var status = LHandler.ReadLFile(out returnCode);
if (logStatus)
{
if (status.SoftLisenceInfoList[0].SoftId2 == Constants.SoftwareId2)
{
StatusParameters1.Value = LogStatus;
}
else
{
StatusParameters1.Value = false;
}
hostSoftware: I want StatusParameters1.Value in my host project MainWindow.xaml.cs file.
Note: I tried to use a delegate but got this error:
No matching constructor found on type MainWindow
Is there any other approach?
EDIT:
I just discovered that there is another project called ServerService which communicated with Console Project and hostSoftware is communicating with ServerService so the data flow is : Console -> ServerService -> hostSoftware.
ServerService is a service which is being used as Service References in hostSoftware
I can understand that you want your service to verify the client, and then the client can call your service. If so, you can refer to Extending WCF, You can choose a suitable way to add security verification to your service.
Related
Looking at the documentation it seems like Windows uses it in 2 scenarios:
The ServiceBase.ServiceName needs to be the same name as when it is installed, however when starting my service I am able to call ServiceBase.Run() without specifying the service name or specifying a different service name altogether and my application still starts correctly. I am using a separate WiX project to install my service and define the service name there depending on some TRANSFORMS.
Windows uses the ServiceBase.ServiceName to specify the EventLog.Source. I am successfully able to use Log4Net's EventLogAppender to log to the EventLog, manually specifying the applicationName in my log4net configs.
I want to make sure that I don't run into any repercussions down the road in the case that I don't specify the ServiceName correctly, however I am currently able to hit all my typical use cases as is. After calling ServiceBase.Run() I am able to use System.Management to determine my service name in case of any additional needs.
My main concern with avoiding setting the service name here is because my MSI installer can install different instances of my exe as different services via TRANSFORMs I create a sort of chicken-and-egg problem where I can't call GetServiceName() without calling ServiceBase.Run(), but I can't call ServiceBase.Run() without defining the ServiceBase.ServiceName.
Some example code of what I am running:
public aync Task<int> RunAsync()
{
var serviceToRun = new ServiceBase{/*ServiceName = "Avoiding.."*/};
var runServiceTask = Task.Run(() => ServiceBase.Run(serviceToRun));
logger.Warn($"ServiceName : '{GetServiceName()}'");
logger.Warn($"Service ShortName : '{serviceToRun.ServiceName}'");
await runServiceTask.ConfigureAwait(false);
return serviceToRun.ExitCode;
}
public string GetServiceName()
{
var processId = Process.GetCurrentProcess().Id;
var query = $"SELECT * FROM Win32_Service where ProcessId = {processId}";
var managementObject = new ManagementObjectSearcher(query).Get().Cast<ManagementObject>().FirstOrDefault();
if (managementObject == null)
{
throw new Exception("Could not get service name");
}
var serviceName = managementObject["Name"].ToString();
return serviceName;
}
I am new to wpf and wcf C# application development and stuck into updating the class where wcf service is referenced. For example, Service has a class of testDbConnect and has various service operation contracts functions defined and implemented in iservice.cs and service.cs. Then in wpf class , this service is added as a reference and works perfect when calls the service functions by button click operation. Like this is what I am testing on button click.
Service1Client service = new Service1Client();
if (service.Testdb() == 1) //Testdb is the function in service which is only returning 1
{
MessageBox.Show("Hello there");
}
The problem I am facing, It perfectly starts service and show the message box( hello there) on button click but when I am updating the code even inside the button click , it still keep showing the hello there message box and not updating code. Maybe there is some proxy generation included but I am not understanding it. It'll be great If someone could explain me in easy words and tell me how It could be solved. Thanks
Based on the way you're consuming your WCF Service you need to update your services references.
Suppose you need to rename int Testdb(); in your service for int TestDb();. You go to your contract (IService1.cs), change the signature to match:
IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
int TestDb();
}
Then go to your service and update your method:
Service1.cs
public class Service1 : IService1
{
public int TestDb()
{
return 1;
}
}
Then, on the server side your good to go, but you need to update your service reference on your client app, so your proxies reflect the new method signature. So in your client app you expand Service References folder, right-click ServiceReference1 - or the name of your service reference - node and select Update Service Reference.
Let Visual Studio update the service reference and then you should be able to call the TestDb method by the new name.
Hope this helps!
I am currently building an SSIS integration package and as part of this I need to access a webservice. Does anybody know of any C# code that can be used to provide variable values to a webservice and then also GET the value that the web service returns.
The SSIS Web Service Task isn't quite as dynamic as I need it to be. The parameters I need to provide are:
• serverName
• databaseName
• hardwareFingerprint
• userName
Try instead adding a Script Task. Within the code editor, right click on References and choose 'Add Web Reference'. Type in the web service endpoint URI, give it a name local to your project and click 'Add Reference'.
Within your ScriptMain.cs file, add a using statement to point to your new web reference, instantiate the service and make the call.
Some example code:
using Company.WebServices;
namespace ST_abcdef.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
WebService1 webService1 = new WebService1();
var result = webService1.methodA("param1", "param2");
// process result
}
}
}
I have written a Windows service, of which I want to have 1 instance running per customer. This is because the customers each have their own DB with identical schemas; the only difference between the Windows services is that they will each have a different parameter corresponding to the customer DB that they're designated to serve. (And I can't have one service with multiple worker threads, because the DB connection uses a static variable, which I can't fiddle with across threads.)
I found this neat little tutorial about how to make a Windows Service, but it only shows me how to set it up for a single service. I want to set up n instances of the service, each one with a display name that includes the customer name, running with the command line parameter that denotes the customer ID.
The tutorial linked above has a class called MyWindowsServiceInstaller, which installs the windows service on the local system, and I'm guessing this would be a logical place to set up a foreach loop through all my customers, setting up one service for each. But I can't see anywhere on the interfaces provided that would allow me to set up a command line parameter for the new service.
How do you do it?
All I wanted was to send one parameter to the service I have created.
As it turns out, all you have to do is (carefully!) edit the registry at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ and add the parameter in ImagePath, after the quotes.
Eg. ImagePath Value Data: "C:\Program Files\myservice\myservice.exe" param1
I found the solution in this link http://social.msdn.microsoft.com/Forums/is/csharpgeneral/thread/38242afa-7e40-4c06-975e-aa97d3cc782f
Wil Peck wrote a good article about how to install multiple instances of a windows service on a single box. The basic idea is that you have to trick the installer into thinking they are different services by giving them different names.
Having said that, it seems like it would be easier (and more maintainable) to redesign your database connection code so that it can support multiple worker threads.
You can pass parameters to your installer using installutil, for example ServiceName and DisplayName.
ProjectInstaller.cs
public partial class ProjectInstaller : Installer
{
protected override void OnBeforeInstall(IDictionary savedState)
{
SetServiceName();
base.OnBeforeInstall(savedState);
}
protected override void OnBeforeUninstall(IDictionary savedState)
{
SetServiceName();
base.OnBeforeUninstall(savedState);
}
private string AppendParameter(string path, char parameter, string value)
{
if (!path.StartsWith("\""))
path = $"\"{path}\"";
if (value.Contains(" "))
value = $"\"{value}\"";
return $"{path} -{parameter}{value}";
}
private void SetServiceName()
{
if (Context.Parameters.ContainsKey("ServiceName"))
serviceInstaller.ServiceName = Context.Parameters["ServiceName"];
if (Context.Parameters.ContainsKey("DisplayName"))
serviceInstaller.DisplayName = Context.Parameters["DisplayName"];
Context.Parameters["assemblypath"] = AppendParameter(Context.Parameters["assemblypath"], 's', serviceInstaller.ServiceName);
}
}
This will append a parameter to the path stored with the service, for example:
Before: "C:\Service.exe"
After: "C:\Service.exe" -s"Instance 1"
You can then read this parameter when you start the service and pass to your services constructor.
Program.cs
static void Main(string[] args)
{
string serviceName = args.Single(x => x.StartsWith("-s")).Substring("-s".Length);
ServiceBase service = new Service(serviceName);
ServiceBase.Run(service);
}
Service.cs
public partial class Service : ServiceBase
{
public Service(string serviceName)
{
InitializeComponent();
ServiceName = serviceName;
}
}
Usage
installutil /ServiceName="Instance 1" /DisplayName="Instance 1 Service" "C:\Service.exe"
installutil /ServiceName="Instance 2" /DisplayName="Instance 2 Service" "C:\Service.exe"
You basically need to install the service several times, and customise it with it's exe.config file.
Alternatively, you can have one service that runs different worker threads for each client.
Update
exe.Config is an Application Configuration File
I have no idea how to use that installer component to install several instances of the service, I wasn't aware you could.
Where we need several instances of one of our services to run on one machine, we actually only install it once, then literally copy the installed folder and change the exe name for the second instance. The second instance is then configured in it's own Application Configuration File.
As far as I known it is impossible to provide startup parameters using either ServiceInstaller, ServiceProcessInstaller or installutil. However, it is possible to provide startup parameters using some COM api's from advapi.dll (check the left menu). A complete collection of the required calls can be found here. It's a class (also) called ServiceInstaller that contains the required external methods and some utility methods.
You'd want to use the utility method InstallAndStart. It accepts a service name, a display name and a path to the executable that represents your Windows service. You can call it like this:
InstallAndStart("MyService", "My Service For User 1",
"c:\\pathtoexe\MyService.exe user1");
If you have the following service the parameter startupParam will receive the value user1.
class Program : ServiceBase
{
private string startupParam;
static void Main(string[] args)
{
string arg = args[0];
ServiceBase.Run(new Program(arg));
}
public Program(string startupParam)
{
this.ServiceName = "MyService";
this.startupParam = startupParam;
}
...
}
I created a WebService using the .NET 2.0 framework, a class based on an interface that has the WebServiceAttribute and hosting it using IIS and a ASMX file. The WebService currently loads its configuration from one XML file.
I'd like to create multiple instance of this service where each loads it own configuration.
By coping the ASMX file I can create a clone of the webservice under a different name which will be based on exact the same implementation. But it also loads the exact same configuration file which makes it rather useless.
So my question is: What is the best way to create an arbitrary number of WebServices that are based on one class, living in one IIS virtual directory where each is loading a different configuration file?
Solution
With the help of Pavel Chuchuva's answer I created the following code to handle the loading of the configuration:
public class WebConfigManager
{
public static T Load<T>() where T: new()
{
string location =
HttpContext.Current.Request.PhysicalPath + ".config";
if (HttpContext.Current.Cache[location] is T)
{
return (T)HttpContext.Current.Cache[location];
}
using (Stream s =
new FileStream(location, FileMode.Open, FileAccess.Read))
{
return (T)(HttpContext.Current.Cache[location] =
new XmlSerializer(typeof(T)).Deserialize(s));
}
}
}
// example of the usage of WebConfigManager
public class MyWebService : IMyWebService
{
Config config = WebConfigManager.Load<Config>();
...
Copy and paste .asmx file to create multiple instances of your web service (e.g. Service1.asmx, Service2.asmx and so on).
Load configuration file based on Context.Request.FilePath value:
public string LoadConfig()
{
string configPath = Server.MapPath(this.Context.Request.FilePath + ".xml");
using (XmlReader reader = XmlReader.Create(configPath))
{
// Will read Service1.asmx.xml, Service2.asmx.xml and so on
}
}
I suggest placing the asmx in different folders and placing a web.config in each of those folders with the setting for that specific instance of the web service. This is the easy and fast way
OR
you could use Web Service Enhancements 3.0 and create a WSE router, redirect a calls to a ASMX to that router and let the router forward the call to the right web service instance and pass additional config. This a more complex way of doing it but it enables u to use a single instance of the web service that's picks the right configuration based on the parameters the router passes it.
For more info on WSE3.0 I point you to the MSDN.
Hope this helps!