How can I create a WCF Service Application in Visual Studio that does NOT use a Web Server - visual-studio

I have a simple task: A program (executable) is supposed to call a function of another program (also executable) with some parameters. Program A is supposed to be started, call the function and then terminate. Program B is legacy program that has a GUI and runs continuously. Both programs run on the same Windows PC and use the .NET Framework. I have no experience in web development and Program B is not supposed to run as a web service! Named pipes seem like a good option.
I researched what the best method would be and wanted to try WCF. The documentation claims that "A service endpoint can be part of a continuously available service hosted by IIS, or it can be a service hosted in an application". From that I understand that I can run Program B as a service without hosting a web server.
However everything I see in Visual Studio seems to presume I want to run a server. Wenn I want to create a new WCF project in Visual Studio the only options are a library or "A project for creating WCF service application that is hosted in IIS/WAS". Once I've created said project the debugger wants me to choose a browser for hosting the service.
In another StackOverflow topic a popular suggestion was using this website as a guide and simply removing the http references since the guide is for both named pipes and http. Another indication that it should be possible.
So can someone point me in the right direction? What am I missing? How can I use WCF with nothing related to Web Development involved?

You have already been on the way, it is enough to host the web service in Program B, without specifying a web server. this is called a self-hosted WCF. As the link you provided mentioned, the Service host class is used to host the WCF service, which means that we can host the service in the Console/Winform, and so on.
Here is an example of hosting the service in a Winform application.
public partial class Form1 : Form
{
ServiceHost serviceHost = null;
public Form1()
{
InitializeComponent();
Uri uri = new Uri("http://localhost:9009");
BasicHttpBinding binding = new BasicHttpBinding();
serviceHost = new ServiceHost(typeof(MyService), uri);
serviceHost.AddServiceEndpoint(typeof(IService), binding, "");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
serviceHost.Description.Behaviors.Add(smb);
System.ServiceModel.Channels.Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
serviceHost.Open();
}
private void Form1_Load(object sender, EventArgs e)
{
if (serviceHost.State==CommunicationState.Opened)
{
this.label1.Text = "Service is running";
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (serviceHost.State==CommunicationState.Opened&&serviceHost.State!=CommunicationState.Closed)
{
serviceHost.Close();
}
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
string Test();
}
public class MyService:IService
{
public string Test()
{
return DateTime.Now.ToLongTimeString();
}
}
After that, we could consume it by using a client proxy.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/accessing-services-using-a-wcf-client
Feel free to let me know if there is anything I can help with.

Related

NET Core Server Side multiple session Blazor

I'm trying to host my Blazor application on my server.
I spent all the summer on it and I just realized every time I open my website on new device it doesn't create a new session restarting from zero, but continues where I left it. The worst part is there is a login system behind it, so I feel super dumb at the moment.
I really need a big hint on how to fix this "not little" issue.
Is there a way to make server create new session every time someone open the website (without making it loose to other users)?
The solution should be use a Client Template instead, but the performance are really to slow.
UPDATE:
Accounts "user password" are:
- user user
- test test
Download project sample (requires Net Core 3.0)
[SOLUTION] itminus found the solution to my issue.
You have also to add in ConfigureServices in Startup.cs this services.AddScoped<Storage>();
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<Storage>();
}
every time I open my website on new device it doesn't create a new session restarting from zero, but continues where I left it.
I checkout your code and find that you're using Singleton Pattern to initialize the Storage. If I understand it correctly, this Storage singleton instance will be shared across different users (also across different devices). As this instance will be used to render the Main.razor page, there will be concurrency problems that you're experiencing now .
To fix that issue, the Storage instance should be limited within some specific connection. As you're using Blazor Server Side, you could register the Storage as a Scoped Service:
In Blazor Server apps, a scoped service registration is scoped to the connection. For this reason, using scoped services is preferred for services that should be scoped to the current user, even if the current intent is to run client-side in the browser.
Firstly, remove the static singleton instance :
public class Storage
{
private static Storage instance;
private Storage()
{
}
public static Storage GetInstance()
{
if (Storage.instance == null)
Storage.instance = new Storage();
return Storage.instance;
}
public List<Items>list {get;set;} = new List<Items>();
public string password {get;set;}
}
Register this Class as a scoped service:
services.AddScoped<Storage>();
And then inject this service in your Login.razor and Main.razor :
#inject project.Storage Storage
Finally, you need change all the Storage.GetInstance(). to Storage.:
Storage.list = Order;
...
Storage.password = password;
I notice that you're also creating the Importer/Additional instance using the Singleton Pattern. I would suggest you should refactor them to use Service Injection in a similar way.

When self-hosting what exactly causes AddressAccessDeniedException : HTTP could not register URL

I am writing a bdd test for a component that will startup phantomjs and hit a specific route on my site and do processing on that. Because the component is fundamentally about automating a phantom instance there is no way to easily stub out the http requests.
So I want to stub out a self-hosted endpoint that will stub out the data I'm after. Because this is a unit test I think its really important for it to run in isolation so I do something like this:
async Task can_render_html_for_slide_async() {
var config = new HttpSelfHostConfiguration("http://localhost:54331");
config.Routes.MapHttpRoute("Controller", "{controller}", new {});
using (var server = new HttpSelfHostServer(config)) {
server.OpenAsync().Wait();
var client = new HttpClient();
var resp = await client.GetStringAsync(config.BaseAddress+"/Stub");
Console.WriteLine(resp);
}
}
public class StubController : ApiController
{
public string Get() {
return "Booyah";
}
}
Which gets me
AddressAccessDeniedException : HTTP could not register URL http://+:54331/
I understand that netsh or Admin mode is required for this but I don't understand why. Nodejs for example runs perfectly fine on windows but has no such requirement.
Also using OWIN directly needs no netsh-ing. So....what's going on?
I wrote an article about it on codeproject, it was done to make it possible for multiple application to share the same port.
You can have both, IIS and Apache (or OWIN in your case) listenening port 80. The routing to the right application is done thanks to the path of the url.
IIS and Apache both would use this driver (http.sys). But you need permission to "reserve" a path.
Administrators are always authorized. For other users, use netsh or my GUI tool HttpSysManager to set ACL.
Any method that requires giving permission via netsh uses a Windows kernel driver to provide http access.
If a library opens a socket itself and handles the http communication that way, no netsh use is needed.
So to answer your question, some methods are using the kernel driver and some are handling the protocol themselves.

IIS Express Returning HTTP 400 for WCF RESTful Service

I have a WCF RESTful Web Service (using webHttpBinding) that is returning a 400 when I try to call a web service method on it.
If I go to mywebservice.svc, I get the standard WCF web service page. But if I go to /mywebservice.svc/some/rest/service/url, I get an Http 400. Every single time. Doesn't matter the parameters, or the method being called.
Here's what we've looked at so far:
Looked at IIS Express logs. There is no Win32 status (i.e. status 0) to go along with the HTTP Status
Turned on WCF logging. Nothing is logged by WCF, which suggests the request isn't even making it that far.
Tried debugging our method, but the breakpoint never gets hit.
Tried running the service under Cassini. Same result (http 400).
Tried another user on the problematic machine. Same result.
We know that this works on other machines. The problematic machine is using VS 2010 on Win XP. We are using WCF 4.0
I know there isn't much to go on here because we don't have a specific error message, but given where we've looked, does anybody have any suggestions on where to look next?
UPDATE: Added Code Samples
Here is the definition of my with one method, and the implementation of that method.
[ServiceContract]
public interface IMAMDataWebService
{
[WebGet(UriTemplate = "/Contracts/{taxID}", ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
ContractCollection Contracts(string taxID);
}
public ContractCollection Contracts(string taxID)
{
ContractCollection contracts = new ContractCollection();
try
{
contracts = _contractService.GetContracts(taxID);
}
catch (RstsException rEx)
{
if (!rEx.Logged)
_errorLogger.LogError(rEx);
WebFault.ThrowFault(rEx, HttpStatusCode.InternalServerError);
}
catch (Exception ex)
{
RstsException rEx = new RstsException(ex);
_errorLogger.LogError(rEx);
WebFault.ThrowFault(rEx, HttpStatusCode.InternalServerError);
}
if (contracts.Count == 0)
{
WebFault.ThrowFault(Strings.ObjectNotFound, HttpStatusCode.NotFound);
}
return contracts;
}
I'm calling it with a web browser, i.e. MAMDataWebService.svc/Contracts/123456789
I'm convinced this has to be a permissions problem, but I"m not sure what. It works on all our Win 7 machines using VS 2010, but a few users still have XP and they're the ones with the problem. But without any errors, it's hard to tell what's going on.

How to speed up Azure deployment from Visual Studio 2010

I have Visual Studio 2010 solution with an Azure Service and an ASP.NET MVC 3 solution that serves as a Web Role for the Azure service. No other roles attached to the service other than that.
Every deployment to the Azure staging (or production, for that matter) environment takes up to 20 minutes to complete, form the moment I click publish on Visual Studio until all instances (2) are started.
As you can imagine this makes it a PITA to publish often, or to quick-fix some bugs. Is there a way to speed the process up? Would it be faster to upload the package to de Blob storage and upgrade from there? How would I go about achieving that?
I feel on-line docs on Azure leave a lot to be desired. Particularly when it comes to troubleshooting by the way.
Thanks.
One idea for reducing the need (and frequency) for redeploying is to move static content into blob storage, external to the package. For instance, move your css and javascript to blob storage, along with images. Once this is done, you'd only have to recompile / redeploy for .NET code changes. You can upload updated css, at any time, to blob storage. If you want to test this in staging first, you could always have a staging vs. production container name for your static content and store that container name in a config setting.
This doesn't change the deployment time when you do need to redeploy, but at least you can reduce how often you go through that process...
You should enable Web Deploy in your Azure project. It works this way :
1/ Create a RDP account (don't forget, you need to upload a certificate with its private key so that Azure can decipher the password). That is hidden in the Deploy Dialog Box for your Azure deployment project.
2/ Enable Web Deployment - same place
Once you've published the app that way, right-click in the web application (not the azure deployment project) and select Publish. The pop-up has everything defined except the password, enter that as well and you'll upload your changes to Azure in a matter of seconds.
CAVEAT : this is meant for single-instance web apps, definitely not the way to go for a production upgrade strategy, and the Blob storage answer already mentioned is the best option in that case.
Pierre
My solution to this problem is only to push a new package when I am changing code in the RoleEntryPoint or with the Service Definition. In Azure 1.3 you now have the ability to use Remote Desktop Connection. Using RDC, I will compile my code locally and use copy/paste to place it on the Azure server in the appropriate directory. Once the production code is running correctly, I can then push the fully tested version to staging and then do a VIP swap. This limits the number of times I actually have to deploy a package.
You actually have quite a long window in which you can keep modifying your code in Azure before you have to publish a new package. The new package is only really needed for those cases where Azure has to shutdown/restart your role instance.
It's a nice idea to try uploading your project to blob storage first, but unfortunately this is what Visual Studio is doing for you behind the scene anyway. As has been pointed out elsewhere, most of the time in doing the deploy is not the upload itself, but the stopping and starting of all of your update domains.
If you're just running this site in a development environment, then the only way I know to speed it up is to run just one instance. If this is the live environment, then... sorry, I think you're out of luck.
So that I don't have to deploy to the cloud to test minor changes, what I've found works quite well is to engineer the site so that it works when running in local IIS just like any other MVC site.
The biggest barrier to this working are settings that you have in the cloud config. The way we get around this is to make a copy of all of the settings in your cloud config and put them in your web.config in the appSettings. Then rather than using RoleEnvironment.GetConfigurationSettingValue() create a wrapper class that you call instead. This wrapper class checks RoleEnvironment.IsAvailable to see if it is running in the Azure fabric, if it is, it calls the usual config function above, if not, it calls WebConfigurationManager.AppSettings[].
There are a few other things that you'll want to do around getting the config setting change events which hopefully you can figure out from the code below:
public class SmartConfigurationManager
{
private static bool _addConfigChangeEvents;
private static string _configName;
private static Func<string, bool> _configSetter;
public static bool AddConfigChangeEvents
{
get { return _addConfigChangeEvents; }
set
{
_addConfigChangeEvents = value;
if (value)
{
RoleEnvironment.Changing += RoleEnvironmentChanging;
}
else
{
RoleEnvironment.Changing -= RoleEnvironmentChanging;
}
}
}
public static string Setting(string configName)
{
if (RoleEnvironment.IsAvailable)
{
return RoleEnvironment.GetConfigurationSettingValue(configName);
}
return WebConfigurationManager.AppSettings[configName];
}
public static Action<string, Func<string, bool>> GetConfigurationSettingPublisher()
{
if (RoleEnvironment.IsAvailable)
{
return AzureSettingsGet;
}
return WebAppSettingsGet;
}
public static void WebAppSettingsGet(string configName, Func<string, bool> configSetter)
{
configSetter(WebConfigurationManager.AppSettings[configName]);
}
public static void AzureSettingsGet(string configName, Func<string, bool> configSetter)
{
// We have to store these to be used in the RoleEnvironment Changed handler
_configName = configName;
_configSetter = configSetter;
// Provide the configSetter with the initial value
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
if (AddConfigChangeEvents)
{
RoleEnvironment.Changed += RoleEnvironmentChanged;
}
}
private static void RoleEnvironmentChanged(object anotherSender, RoleEnvironmentChangedEventArgs arg)
{
if ((arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName == _configName)))
{
if ((_configSetter(RoleEnvironment.GetConfigurationSettingValue(_configName))))
{
RoleEnvironment.RequestRecycle();
}
}
}
private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
{
// If a configuration setting is changing
if ((e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)))
{
// Set e.Cancel to true to restart this role instance
e.Cancel = true;
}
}
}
The uploading itself takes a bit more than a minute most of the time. It's the starting up of the instances that take up most of the time.
What you can do is to deploy your fixes to staging first (note that it costs money so don't let it be there for too long). Swapping from staging to production only takes a couple of seconds. So while your application's still running you can upload the patched version, let your testers test it on staging and when they give the go then simply swap it to production.
I haven't tested your possible alternative approach by first uploading to blob storage first. But I think that's overhead as it doesn't speed up starting up the instances.

.NET IE BHO Remoting

I have a IE Browser Helper Object, which is a Toolbar addin for IE 8.
I have another .NET .EXE application (Remoting Client) that connects to this BHO (Remoting Server) using remoting via common Interface.
When I test the communication between the .EXE application and a TEMP Console application with the same code used in the Server component, it communicates fine, and runs the remote Method.
However, when i try and communicate with the BHO server with security on the TCP cahannel ON ChannelServices.RegisterChannel(tcpClientChannel, true); , I get a "FileNotFoundException" Could not load file or assembly "xxxx" which "xxxx" is the common Interface assembly that contains the Server Methods.
When i try and communicate with the BHO server with security on the TCP cahannel OFF ChannelServices.RegisterChannel(tcpClientChannel, false); , I get error "connection to the remote object was forcably closed".
If I re-test it with the simple test console app it work.
Im starting to believe the problem is with the way remoting works inside a BHO instance... Has anyone used Remoting in a BHO .NET instance, Im using the SPICIE library to create the BHO using .NET.
COMMON Interface assembly for Remoting Interface Object
namespace WWie.CommonClasses
{
class WWieRemote : MarshalByRefObject, WWieClassLibrary.WWieCommonClass.IGetHtmlElement
{
public string GetElementClicked()
{
return ("Returned from WWieRemote ");
}
public void SetElementClicked(string str)
{
MessageBox.Show("SetElement " + str);
}
}
}
CLIENT APP
static TcpChannel tcpClientChannel = new TcpChannel();
public static WWieClassLibrary.WWieCommonClass.IGetHtmlElement remoteObject;
ChannelServices.RegisterChannel(tcpClientChannel, false);
remoteObject = (WWieClassLibrary.WWieCommonClass.IGetHtmlElement)Activator.GetObject(typeof(WWieClassLibrary.WWieCommonClass.IGetHtmlElement), "tcp://localhost:9002/TestWWie");
testing with remote method call
remoteObject.SetElementClicked("from Client");
SERVER BHO
TcpChannel tcpServerChannel = new TcpChannel(9002);
ChannelServices.RegisterChannel(tcpServerChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(WWieClassLibrary.WWieCommonClass.IGetHtmlElement), "TestWWie", WellKnownObjectMode.Singleton);
Since IE is running in protected mode by default, it usually doesn't have access to communicate with higher integrity processes. If your url is in the intranet zone, you can push a policy that disable protected mode for the intranet zone.
Otherwise you may want to look for other options, like shared memory, named pipe, hidden worker windows & registered messages & customized message filter for Vista's UIPI, etc.

Resources