How to publish WCF web service (created in CodeGear Delphi for .NET) on IIS? - wcf

I succeeded to create WCF web service in CodeGear Delphi for .NET 2007/2009.
I use this tutorial:
https://community.embarcadero.com/blogs/entry/building-net-35-wcf-restful-web-services-with-delphi-2007-38508
In this article they created console application and tested web service in it.
But i need to publish this WCF web service on IIS - how can I do that?
UPDATE:
I tried to make dll (not console app) and my work looks like this:
1) unit uServiceIntf.pas
unit uServiceIntf;
interface
uses
System.ServiceModel,
System.ServiceModel.Web;
type
[ServiceContract(Namespace = 'http://localhost:3000/')]
IService = interface
[OperationContract]
[WebGet(UriTemplate='Add?a={x}&b={y}')]
function Add(x, y: integer): integer;
end;
implementation
end.
2) unit uServiceImpl.pas
unit uServiceImpl;
interface
uses
uServiceIntf;
type
TService = class(TObject, IService)
public
function Add(x, y: integer): integer;
end;
implementation
{ TService }
function TService.Add(x, y: integer): integer;
begin
Result := x + y;
end;
end.
3) DelphiRESTBasicSample_Service_dll.dpr
library DelphiRESTBasicSample_Service_dll;
uses
SysUtils,
Classes,
System.Reflection,
System.Runtime.InteropServices,
uServiceImpl in 'uServiceImpl.pas',
uServiceIntf in 'uServiceIntf.pas';
[assembly: AssemblyTitle('')]
[assembly: AssemblyDescription('')]
[assembly: AssemblyConfiguration('')]
[assembly: AssemblyCompany('')]
[assembly: AssemblyProduct('')]
[assembly: AssemblyCopyright('')]
[assembly: AssemblyTrademark('')]
[assembly: AssemblyCulture('')]
[assembly: AssemblyVersion('1.0.*')]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile('')]
[assembly: AssemblyKeyName('')]
[assembly: ComVisible(False)]
begin
end.
4) DelphiRESTBasicSample_Service_dll.svc:
<%# ServiceHost Language="C#" Service="DelphiRESTBasicSample_Service_dll.TService" %>
5) web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="returnFaults" name="DelphiRESTBasicSample_Service_dll.TService">
<endpoint address="Add" binding="basicHttpBinding" contract="IService">
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:3000/DelphiRESTBasicSample_Service_dll.svc"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<directoryBrowse enabled="false" />
</system.webServer>
</configuration>
6) Publish on IIS:
I put svc-file and web.config file in folder D:\MySite and dll-file in folder D:\MySite\bin.
I give all rights to folder D:\MySite for user IIS_IUSRS.
I make a site:
7) Result:
I try this in Chrome browser:
a) http://localhost:3000/Add?a=2&b=3
b) http://localhost:3000/DelphiRESTBasicSample_Service_dll.svc/Add?a=2&b=3
Both don't work.
What am i doing wrong?

Read this page: https://www.ojdevelops.com/2017/10/deploying-web-application-to-local-iis.html
It says the steps are as follows:
Besides that, if you want to have a specific URL that's not related to localhost, then add the URL you desire to be local to hosts, mapped to 127.0.0.1. In that case you will also need to set the host headers at IIS, see: https://docs.revenera.com/isxhelp23/helplibrary/IISHostHeader.htm

Maybe you can start by looking at the official documentation, which will guide you through the hosting service step by step.

Related

Does Visual Studio Online support SOAP WorkItem change notification?

The reason I ask, is that I've set up a WCF service following the guidance out there (specifics below), and set up a SOAP notification in Visual Studio Online and my service doesn't appear to be called. IIS 8.5 Logs show no attempt to make contact with the service from VSO servers.
In case it IS supported, here are relevant bits to see if I have something set up wrong on the service side.
WCF Service - .NET 4.5.1 hosted as an Azure WebRole
Contract and Implementation
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface IWorkItemSubscriber
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
// Note, I've tried w/ and w/out this Compatibility Attribute
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WorkItemSubscriber : IWorkItemSubscriber
{
public void Notify(string eventXml, string tfsIdentityXml)
{
// Do stuff
}
}
Web.Config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="noSecurity">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="VsoNotificationService.Wcf.WorkItemSubscriber" behaviorConfiguration="eventServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="noSecurity" contract="VsoNotificationService.Wcf.IWorkItemSubscriber" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="eventServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" aspNetCompatibilityEnabled="true" /> <!-- note: I've tried w/ and w/out the aspNetCompatibilityEnabled attribute -->
</system.webServer>
</configuration>
Visual Studio Online Configuration
I've confirmed I can hit the service, via creating my own client and calling the service. Whatever code I put in the method is executed, and if I do remote debugging via Visual Studio 2013 I'll hit the method's breakpoint. So the service is up and running, I just don't see traffic from Visual Studio Online (via code breakpoint, code content, nor IIS Logs). Makes me think that feature is not working there?
I see that you are missing the aspNetCompatibilityEnabled="true" on the <serviceHostingEnvironment element, as compared to my working solution, it might be the missing piece of the puzzle?
I only also achieved success by carefully including all little config settings.

C# 4.0 WCF REST JSON - HTTP GET CODE 400 Bad Request

When trying to create a simple service to return a simple JSON string by following several tutorials. I get stuck on two different machines with a HTTP Statuscode 400 bad request.
Example tutorials
RESTful WCF Service with JSON pt.1 & pt.2 - http://www.youtube.com/watch?v=5BbDxB_5CZ8
I have also Google and searched here (StackOverflow) for similar problem without success.
The problem is I get the 400 bad request when trying to do a sanity check to browse to the WCF service and execute the method. By compiling the service and browse this address: http://localhost:49510/Service1.svc/GetPerson
Just like the tutorial. I have tried finding a solution for like 3 days. Any help is appreciated.
This is what I do.
First i create a new project a simple WCF Service application. I delete the default Service1.svc and add a new WCF Service, that generate a new Service1.svc and a IService1.cs
Here is the code for the interface (IService1.cs)
namespace WcfService1
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method="GET", BodyStyle=WebMessageBodyStyle.Bare, ResponseFormat=WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json, UriTemplate="GetPerson")]
Person GetPerson();
}
[DataContract(Name="Person")]
public class Person
{
[DataMember(Name="name")]
public string Name { get; set; }
}
}
Here is the code for the Service1.svc
namespace WcfService1
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public Person GetPerson()
{
return new Person() { Name = "Tobbe" };
}
}
}
And the Web.config is untouched and look likes this web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
For REST WCF You have to do binding and endpoint setting in web.config
Replace your whole web.config by following and it will work
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
You were remaining with following 2 things
Use webHttpBinding (change default http port mapping to webHttpBinding)
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<behaviors>
<system.serviceModel>
Specify webHttp End Point Behaviors
<system.serviceModel>
-----
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior >
</endpointBehaviors>
<behaviors>
------
<system.serviceModel>
You didn't specify any endpoint... By default on WCF 4, an endpoint using basicHttpBinding will be used. It'll not work here because it is a SOAP-based binding. What you want to use is webHttpBinding which is REST-based...
Here is how to override default binding with WCF 4 :
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
You also have to enable webHttp by adding this endpoint behavior in your config :
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior >
</endpointBehaviors>
<behaviors>
http://msdn.microsoft.com/en-us/library/bb924425.aspx
I'm not entirely sure why, but when I added the 'Factory' attribute to my .SVC file (you need to explicitly drag it to Visual Studio), everything just works - without any changes to default settings in Web.config!
I added Factory="System.ServiceModel.Activation.WebServiceHostFactory" so my .SVC file went from this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" %>
to this:
<%# ServiceHost Language="C#" Debug="true" Service="ServiceNameSpace.ServiceName" CodeBehind="ServiceName.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
The only side effect seems to be that when you click on the .SVC file in the browser, you get an 'Endpoint not found' error, but the service works fine when you invoke it correctly anyway. As mentioned previously, I'm using a default Web.config with .NET 4.6 (Simplified WCF configuration), so I may yet need to add endpoint details for that to work again.
Note to moderator: my apologies for posting this answer on a couple of questions. Won't do it again. However, I don't think that deleting it from BOTH questions was very balanced. This is why I have re-posted this answer here only.

Windows service hosting a WCF service closing immediately

I tried hosting a WCF Library service with windows service project, I installed the service, however, when i start the service in services.msc, the service start and closses immediatly. Following the message that gets displayed:
The Servicel service on Local
Computer started and then stopped.
Some services stop automatically if
they are not in use by other services
or programs.
The App.config file for wcf and the windows service project is same and it is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="WorkMateWCF.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
contract="WorkMateWCF.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8523/WorkMate1" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The entire project/solution is downloadable here: https://skydrive.live.com/?cid=d358d316fa2c3a37&sc=documents&uc=1&id=D358D316FA2C3A37%21135#
Could you please guide me on how to proceed further. Thank you.
Additional information:
Following is the code from the service1.cs file in windows service project.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.ServiceModel;
using WorkMateWCF;
namespace WorkMateWinService
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost MyServiceHost = null;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
}
MyServiceHost=new ServiceHost(typeof( Service1));
MyServiceHost.Open();
}
protected override void OnStop()
{
if (MyServiceHost != null)
{
MyServiceHost.Close();
MyServiceHost = null;
}
}
}
}
What I find very confusing (and probably the .NET runtime, too) is the fact that your Windows Service is called Service1, while your WCF Service also is called Service1 (without a namespace or anything).
So which of the two Service1 class types will be used here???
MyServiceHost = new ServiceHost(typeof(Service1));
I'm not sure - and I'm afraid it will be the wrong class (the Windows NT Service class).
You should give your stuff more meaningful names and keep those things apart (by name, too) !
Got the issue, when I reviewed my event logs I found this:
"Service cannot be started. System.InvalidOperationException: The HttpGetEnabled property of ServiceMetadataBehavior is set to true and the HttpGetUrl property is a relative address, but there is no http base address. Either supply an http base address or set HttpGetUrl to an absolute address.
at System.ServiceModel.Description.ServiceMetadataBehavior.EnsureGetDispatcher(ServiceHostBase host, ServiceMetadataExtension mex, Uri url, String scheme)
at System.ServiceModel.Description.ServiceMetadataBehavior.CreateHttpGetEndpoints(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtension mex)
at System.ServiceModel.Description.ServiceMetadataBehavior.ApplyBehavior(ServiceDescription description, ServiceHostBase host)
at System.ServiceModel.Description.ServiceMetadataBehavior.System.ServiceModel.Description.IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescript..."
Then after thorough reviewing, the issues is that I did HTTPSGETENABLED to false only for one, infact there are two, after making the change for the other one, the app started to work like charm.
I special

How to use a WCF service with HTTP Get (within Visual studio 2010)

We've tried to use a very very simple WCF service with a HTTp Get and we can't get it work.
We've followed those "guide" but it doesn't work
http://msdn.microsoft.com/en-us/library/bb412178.aspx
http://www.dotnetfunda.com/articles/article779-simple-5-steps-to-expose-wcf-services-using-rest-style-.aspx
When we call our service with the following url, we get a page not found error:
http://localhost:9999/Service1.svc/GetData/ABC
The base url (http://localhost:9999/Service1.svc) works fine and returns the wcf service information page correctly.
Those are the steps and code to reproduce our example.
In Visual Studio 2010, create a new "WCF Service Application" Project
Replace the IService interface with this code
[ServiceContract()]
public interface IService1
{
[OperationContract()]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetData/{value}")]
string GetData(string value);
}
Replace the Service class with this code
public class Service1 : IService1
{
public string GetData(string value)
{
return string.Format("You entered: {0}", value);
}
}
The web.config look like this
<system.web>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Service1">
<endpoint address="" binding="webHttpBinding" contract="IService1" behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior1">
<webHttp helpEnabled="True"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
Press Run and try to call the Get method
If someone get this or something similar working, it would be very kind if you could reply information about the working example.
Thank you very much
I recreated your sample - works like a charm.
One point: do your service contract (public interface IService1) and service implementation (public class Service1 : IService1) exist inside a .NET namespace??
If so, you need to change your *.svc and your web.config to include:
<services>
<service name="Namespace.Service1">
<endpoint address="" binding="webHttpBinding"
contract="Namespace.IService1"
behaviorConfiguration="WebBehavior1">
</endpoint>
</service>
</services>
The <service name="..."> attribute and the <endpoint contract="..."> must include the .NET namespace for this to work.

Subscribing to TFS events and WCF

Sorry for asking a question about something I don't know much about, but I've been pulling my hair out trying to get this working.
So, I have a WCF service that is hosted on IIS and seems to be working insomuch that I can "see" it on the network by going to http://servername/MyService.svc in a browser.
That .svc looks like:
<% #ServiceHost Service="Foo.Bar" %>
The relevant code looks like:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
public interface IBar
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
and:
public class Bar : IBar
{
public void Notify(string eventXml, string tfsIdentityXml)
{
// Just some test output to see if it worked
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "tfs.txt");
File.WriteAllText(path, tfsIdentityXml + eventXml);
}
}
That's all been built and the ensuing .dll put into the bin dir in the site root in IIS.
I now want to subscribe via bissubscribe.exe (or a similar method) to TFS check-in events. I tried doing something like:
bissubscribe /eventType CheckinEvent
/address http://servername/MyService.svc
/deliveryType Soap
/server mytfsserver
But nothing; it doesn't even look like there was log activity. So keeping in mind I know nothing about WCF, what am I doing wrong? I imagine the address param is one thing; am I not supposed to point it to the .svc?
I have created a blog post how you can use WCF in combination with the Event Services of TFS: http://www.ewaldhofman.nl/post/2010/08/02/How-to-use-WCF-to-subscribe-to-the-TFS-2010-Event-Service-rolling-up-hours.aspx
TFS 2010 and WCF 4.0 configurations are described below...
Method signature:
public void Notify(string eventXml) /* No SubscriptionInfo! */
Web config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="Microsoft.TeamFoundation, Version=10.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="NotificationServiceBehavior" name="TF.CheckinListener.CheckinListener">
<endpoint address="Notify" binding="wsHttpBinding" bindingConfiguration="noSecurity" contract="TF.CheckinListener.ICheckinListener" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="NotificationServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
</binding>
<wsHttpBinding>
<binding name="noSecurity" maxBufferPoolSize="20000000" maxReceivedMessageSize="200000000">
<readerQuotas maxStringContentLength="200000000" maxArrayLength="200000000" />
<security mode="None" />
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Subscription address for bissubscribe:
http://MachineName/VirtualDirectoryName/Service.svc/Notify
One point that jumps out is the fact you have a method that doesn't return anything except void. Those should be marked as "one-way" method in WCF:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06Services/Notification/03")]
public interface IBar
{
[OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*", IsOneWay=true)]
[XmlSerializerFormat(Style = OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml);
}
Add the "IsOneWay=true" to your [OperationContract] attribute.
Other than that, there's nothing obviously wrong in your code, but to really tell, we'd need a lot more config info to really tell. Try the IsOneWay=true first and see if that solves your issue.
How is your service configured? In particular, is it configured to use basicHttpBinding?
Try creating a client to call your service to make sure it can be called.
Then, see if there's an example service from the TFS SDK - see if you can get the example to work.
I was able to complete this connection with the following:
[ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
public interface ITeamSystemObserver : IObservable
{
[OperationContract( Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", ReplyAction = "*" )]
[XmlSerializerFormat(Style=OperationFormatStyle.Document)]
void Notify(string eventXml, string tfsIdentityXml, SubscriptionInfo SubscriptionInfo);
}
Note you are missing the SubscriptionInfo parameter. Here is my web.config:
<basicHttpBinding>
<binding name="TfsEventServiceBasic">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
</binding>
</basicHttpBinding>