Hi guys I just want a simple WinForm app with one button. When I press the button
i want to start the selfhosted WCF service. I want to able to connect to this service with for example another client app (winforms) by just adding a service reference.
However the solution that I created is not working. I can't get connected with adding a service reference to this service. I don't actually know what address to call than except the address that I defined in the app.config file. Any help would be great.
Here is the app.config file.
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService">
<endpoint address="http://192.168.0.197:87" binding="basicHttpBinding"
bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat"/>
</service>
</services>
</system.serviceModel>
</configuration>
And forms code:
namespace WindowsFormsApplication11
{
public partial class Form1 : Form
{
public ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_host = new ServiceHost(typeof(WmsStatService));
_host.Open();
}
}
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string sayHello(string name);
}
public class WmsStatService : IWmsStat
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
}
}
I changed the app.config file. The problem is solved. Also thanks for the tips and your answers. The config is changed to.
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.197:87/" />
</baseAddresses>
</host>
<endpoint address="http://192.168.0.197:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The host should open on http://192.168.0.197:81 as in the config file.
So once the host is up and running then, try and broswe to it using the service reference.
I assume that the address is that your machine, and you don't have anything else on that port address. The other things to check are firewalls blocking that port.
I would not have the service class that implements the service contract (interface) be the form - make it a separate interface, a separate class. The reasoning behind this is the fact that the service host will have to create (instantiate) one instance of the service class for each request it needs to handle --> make those classes as small as possible and don't bloat them by baggage (like the Winform) that they don't need for their job!
Then instantiate a ServiceHost inside your Winform - but make that a global member variable of the form! Otherwise, the ServiceHost is gone once your ButtonClick event is finished!
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string sayHello(string name);
}
public class YourServiceClass : IWmsStat
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
}
public partial class Form1 : Form
{
private ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
_host = new ServiceHost(typeof(YourServiceClass));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
_host.Open();
}
Don't mix the class that contains the ServiceHost, with the ServiceClass (which will need to be instantiated by the host to satisfy incoming requests) - the Service implementation should be standalone, and as lean as possible!
Also, it's good practice to follow the Single Responsability Principle - one class should have one job and one job only - don't pack up your whole app logic into a single, huge class - separate out the different jobs into separate classes and compose those together.
Marc
Related
I am developing a WPF application that uses Entity Framework v.6 with the approach Code First to build and manage a local database which is created on the client computer itself.
When I install the application on a client computer and launch it, I receive the following error when the context tries to create the database:
Expansion of |DataDirectory| failed while processing the connection string. Ensure that |DataDirectory| is set to a valid fully-qualified path.
In app.config I have set the following configuration of Entity Framework:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb"/>
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
</providers>
</entityFramework>
My context class contains the following code:
class EntityContext : DbContext
{
public DbSet<Car> Cars { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Volunteer> Volunteers { get; set; }
public DbSet<Motivation> Motivations { get; set; }
public DbSet<PaymentType> PaymentTypes { get; set; }
public EntityContext() : base("StaccoDataBase")
{
System.Data.Entity.Database.SetInitializer(new CreateDatabaseIfNotExists<EntityContext>());
}
}
I have tried to fix the problem setting the |DataDirectory| in the App.xaml.cs as follows:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("DataDirectory", Directories.DBDirectory);
}
But the issue still persists.
I would really appreciate if someone can help me.
Just a wild guess - what if you used this connection string:
Data Source=(LocalDb)\\MSSQLLocalDB; AttachDBFilename=|DataDirectory|StaccoDataBase.mdf; integrated security=SSPI
First of all, use the |DataDirectory| directly in your connection string (don't "inject" it via that string.Format() call), and secondly, add the .mdf extension to the database file you want to attach.
Also, I'd store this connection string in the app.config - don't create it at runtime, because the constructor call here:
public EntityContext() : base("StaccoDataBase")
will try to find StaccoDataBase as a connection string name in your config file.
So use this:
app.config:
<configuration>
.....
<connectionStrings>
<add name="StaccoDataBase"
connectionString="Data Source=(LocalDb)\\MSSQLLocalDB;AttachDBFilename=|DataDirectory|StaccoDataBase.mdf; integrated security=SSPI"
providerName="System.Data.SqlClient" />
<connectionStrings>
.....
</configuration>
I have 5 SilverLight projects in my ASP .NET MVC 4 application. For each of these projects, there is a web service which passes data to and from the silverlight control.
When we deploy the application on the client's server, we update the .ClientConfig file of each SilverLight project by changing the address of the web service.
That is we change -
<endpoint address="http://localhost:52213/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
to -
<endpoint address="http://192.168.5.48/SCHEME/SchemeReimbursementMasterService.asmx"
binding="basicHttpBinding" bindingConfiguration="SchemeReimbursementMasterServiceSoap"
contract="SchemeServiceReference.SchemeReimbursementMasterServiceSoap"
name="SchemeReimbursementMasterServiceSoap" />
Then we build it and publish the application.
So, in future, if the address changes, we would have to change it in all the five .ClientConfig files and build/publish it again. Is there any way we can remove this hardcoding so that it figures out the base part of the url (i.e: http://192.168.5.48/SCHEME/) on its own.
In my application's web.config, I added keys for the service names.
<appSettings>
<add key="ReviewUrl" value="ReviewClaimsService.asmx"/>
<add key="ReimbursementUrl" value="SchemeReimbursementMasterService.asmx"/>
<add key="DiscountUrl" value="DiscountMasterSchemeService.asmx"/>
</appSettings>
In the controller, I created the URL using the HttpContext and the service name from web.config and passed it to the view.
var baseUrl = "http://" + HttpContext.Request.Headers["Host"];
var applicationPath = HttpContext.Request.ApplicationPath;
if (applicationPath == "/")
baseUrl = baseUrl + "/";
var url = baseUrl + ConfigurationManager.AppSettings["ReimbursementUrl"];
In the View, I passed this URL to the silverlight control using InitParams.
<object id="TownsGrid" data="data:application/x-silverlight-2," type="application/x-silverlight-2">
<param name="InitParams" value="ControlName=TownDataGrid,ServiceUrl=#Model.ServiceUrl" />
<param name="source" value="#Url.Content("~/ClientBin/SilverlightApplication.xap")"/>
</object>
In the Application_Startup method of the silverlight project, I passed the URL on to the SilverLight control.
private void Application_Startup(object sender, StartupEventArgs e)
{
var url = e.InitParams["ServiceUrl"];
this.RootVisual = new SilverlightApplication.TownDataGrid(url);
}
And finally, in the silverlight control, I assign the url to the endpoint.
public TownDataGrid(string serviceUrl)
{
InitializeComponent();
EndpointAddress endpoint = new EndpointAddress(serviceUrl);
BasicHttpBinding binding = new BasicHttpBinding();
client = new SchemeReimbursementMasterServiceSoapClient(binding,endpoint);
}
I'm tryin to run a WCF service within a Windows Forms Application. I copied and modified code found in the WCF samples from Microsoft. When running the WCF Sample the service shows up in a port monitor (CurrPorts) I use. When I run my code I can't see my service...
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace NoName.Server
{
[ServiceContract(Namespace="http://NoName")]
public interface IApplicationService
{
[OperationContract()]
NoName.Entities.MediaParameter[] GetParametersForMediaObject(string mediaObjectId);
[OperationContract()]
NoName.Entities.MediaParameter GetMediaParameter(string parameterId);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NoName.Server
{
public class ApplicationService : IApplicationService
{
public Entities.MediaParameter[] GetParametersForMediaObject(string mediaObjectId)
{
throw new NotImplementedException();
}
public Entities.MediaParameter GetMediaParameter(string parameterId)
{
throw new NotImplementedException();
}
}
}
I'm running it from a Form as
private void toolStripButton1_Click(object sender, EventArgs e)
{
using (ServiceHost host = new ServiceHost(typeof(ApplicationService)))
{
host.Open();
}
}
And the configuration in app.config:
<system.serviceModel>
<services>
<service name="NoName.Server.ApplicationService" behaviorConfiguration="ApplicationServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/NoName/ApplicationService"/>
</baseAddresses>
</host>
<!-- this endpoint is exposed at the base address provided by host: http://localhost:8000/NoName/ApplicationService -->
<endpoint address="" binding="wsHttpBinding" contract="NoName.Server.IApplicationService"/>
<!-- the mex endpoint is exposed at soap.tcp://localhost:8000/NoName/ApplicationService/mex -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<!--For debugging purposes set the includeExceptionDetailInFaults attribute to true-->
<behaviors>
<serviceBehaviors>
<behavior name="ApplicationServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
It compiles without errors, no exceptions when I run it. It just won't exist. Ideas?
Well - you're using a using block, which is normally a good thing - but here, the service host will be closed again right away at the end of the using block - which is certainly not what you want!
using (ServiceHost host = new ServiceHost(typeof(ApplicationService)))
{
host.Open(); // host is opened here
} // host is disposed and closed here
So your ServiceHost was open and ready to receive requests - for a fraction of a second only... and then it was closed and disposed of since the using { .. } block ended.....
What you need to do is this:
add a private member variable to e.g. your main form
private ServiceHost _serviceHost = null;
open that service host at some point in your code, e.g. in your method you have there:
private void toolStripButton1_Click(object sender, EventArgs e)
{
_serviceHost = new ServiceHost(typeof(ApplicationService));
}
leave it open until e.g. the Winforms app closes (or the user choses some other menu item to actually close the service host)
Im building a WPF 3.5 desktop app that has a self-hosted WCF service.
The service has an PollingDuplexHttpBinding endpoint defined like so:
public static void StartService()
{
var selfHost = new ServiceHost(Singleton, new Uri("http://localhost:1155/"));
selfHost.AddServiceEndpoint(
typeof(IMyService),
new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll) {ReceiveTimeout = new TimeSpan(1,0,0,0)},
"MyService"
);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
selfHost.Open();
}
Note: the IPolicyRetriever is a service that enables me to define a policy file
This works and I can see my service in my client Silverlight application. I then create a reference to the proxy in the Silverlight code like so:
EndpointAddress address = new EndpointAddress("http://localhost:1155/MyService");
PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding(PollingDuplexMode.MultipleMessagesPerPoll);
binding.ReceiveTimeout = new TimeSpan(1, 0, 0, 0);
_proxy = new MyServiceClient(binding, address);
_proxy.ReceiveReceived += MessageFromServer;
_proxy.OrderAsync("Test", 4);
And this also works fine, the communication works!
But if I leave it alone (i.e. dont sent messages from the server) for longer than 1 minute, then try to send a message to the client from the WPF server application, I get timeout errors like so:
The IOutputChannel timed out attempting to send after 00:01:00. Increase the timeout value passed to the call to Send or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.
Its all running on localhost and there really should not be a delay, let alone a 1 minute delay. I dont know why, but the channel seems to be closed or lost or something...
I have also tried removing the timeouts on the bindings and I get errors like this
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it has been Aborted
How can I try to find out whats wrong here?
WPF uses wsDualHttpBinding, Silverlight - Polling Duplex.
WPF solution is simple; Silverlight requires ServiceHostFactory and a bit more code. Also, Silverlight Server never sends messages, rather Client polls the server and retrieves its messages.
After many problems with PollingDuplexHttpBinding I have decided to use CustomBinding without MultipleMessagesPerPoll.
web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SlApp.Web.DuplexServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="SlApp.Web.DuplexServiceBehavior" name="SlApp.Web.DuplexService">
<endpoint address="WS" binding="wsDualHttpBinding" contract="SlApp.Web.DuplexService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
DuplexService.svc:
<%# ServiceHost Language="C#" Debug="true" Service="SlApp.Web.DuplexService" Factory="SlApp.Web.DuplexServiceHostFactory" %>
DuplexServiceHostFactory.cs:
public class DuplexServiceHostFactory : ServiceHostFactoryBase
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
return new DuplexServiceHost(baseAddresses);
}
}
class DuplexServiceHost : ServiceHost
{
public DuplexServiceHost(params Uri[] addresses)
{
base.InitializeDescription(typeof(DuplexService), new UriSchemeKeyedCollection(addresses));
}
protected override void InitializeRuntime()
{
PollingDuplexBindingElement pdbe = new PollingDuplexBindingElement()
{
ServerPollTimeout = TimeSpan.FromSeconds(3),
//Duration to wait before the channel is closed due to inactivity
InactivityTimeout = TimeSpan.FromHours(24)
};
this.AddServiceEndpoint(typeof(DuplexService),
new CustomBinding(
pdbe,
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()), string.Empty);
base.InitializeRuntime();
}
}
Silverlight client code:
address = new EndpointAddress("http://localhost:43000/DuplexService.svc");
binding = new CustomBinding(
new PollingDuplexBindingElement(),
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()
);
proxy = new DuplexServiceClient(binding, address);
I have created a very basic service operation that needs to write content to my database. This service looks like the following:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
public class myService : ImyService
{
public MyServiceResult MyMethod(string p1, string p2)
{
try
{
// Do stuff
MyResponseObject r = new MyResponseObject();
r.Property1 = DateTime.Now;
r.Property2 = "Some other data";
return r;
}
catch (Exception ex)
{
return null;
}
}
}
ImyService is defined as shown here:
[ServiceContract]
public interface ImyService
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped)]
MyServiceResult MyMethod(string p1, string p2);
}
This service will be exposed to both WP7 and iPhone client applications. Because of this, I believe I need to use webHttpBinding. This has caused me to use the following settings in my web.config file:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="myServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="myService">
<endpoint address=""
behaviorConfiguration="myServiceBehavior"
binding="webHttpBinding"
contract="ImyService" />
</service>
</services>
</system.serviceModel>
Both the service and WP7 app are part of the same solution. I can successfully add a reference to the service in my application. When I run the application though, the page that references the service throws an error. The error says:
Could not find default endpoint element that references contract 'MyServiceProxy.ImyService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
What am I doing wrong? It just seems like this should be a pretty straightforward thing. Thank you for your help.
Have you copied the file "ServiceReferences.ClientConfig" into your Windows Phone 7 project? This file is in your WCF project. Also, WP7 clients support basicHttpBinding only. So, you may see an empty "ServiceReferences.ClientConfig" file unless you switch over to basicHttpBinding