WCF服务无法在托管服务器上运行的原因

Why WCF Service cannot run on hosted server?

本文关键字:运行 服务器 服务 WCF      更新时间:2023-09-26

我在ASP上创建了一个WCF服务。NET网站。但是,当我在托管服务器上运行网站时(例如在realdomainsomedomain.com上(,WCF服务无法运行或被javascript的任何请求调用。它只能在我的本地主机上运行。

这是我的web.config文件中的配置;它在配置标签中只有一些xml行:

<configuration>
<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <behaviors>
      <endpointBehaviors>
        <behavior name="ServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Service">
        <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
          binding="webHttpBinding" contract="Service" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

web.config中的信息由Visual Studio 2008在创建WCF服务时生成。服务行为名为"ServiceAspNetAjaxBehavior",在端点标记中,它也进行了定义。它使用webHttpBiding为客户端调用web服务。

Service.svc文件只有一行:

<%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

我的网站根目录App_Code文件夹中的Service.cs文件。Service.cs的内容如下。因为Service.cs有太多的行,所以我只发布了一些代码示例,让您看到Service.cs文件的基本构造函数。

using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;
using System.Collections;
using DotNetNuke.Entities.Users;
[ServiceContract(Namespace = "IELTSpedia")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service
{
    public Class1 class1 = new Class1();
    public static string defaultPortalAlias = Class1.GetDefaultPortalAlias1();
    public static string testViewPage = "";
    /// <summary>
    /// Reads the available products to provide data for the Kendo Grid
    /// </summary>
    /// <returns>All available products</returns>
    [OperationContract]
    [WebInvoke(ResponseFormat = WebMessageFormat.Json,
                  RequestFormat = WebMessageFormat.Json)]
    public DataSourceResult Read(int skip, int take, IEnumerable<Sort> sort, Filter filter)
    {
        take = skip + take;
        skip = skip + 1;
        return new DataSourceResult();
    }
}

Service.cs文件有一个方法"Read",当使用javascript调用时,该方法将返回一个对象来填充客户端网页上的网格视图。我用来调用该服务的javascript函数如下:

read: {
    url: "http://localhost:8698/dotnetnuke_community_06.02.01_install/Service.svc/Read", //specify the URL which data should return the records. This is the Read method of the Products.svc service.
    contentType: "application/json; charset=utf-8", // tells the web service to serialize JSON
    type: "POST" //use HTTP POST request as the default GET is not allowed for svc
},
parameterMap: function(data, operation) {
    if (operation != "read") {
        // web service method parameters need to be send as JSON. The Create, Update and Destroy methods have a "products" parameter.
        return JSON.stringify({ service: data.models })
    } else {
        return JSON.stringify(data);
    }
}

在javascript中;我已经通过我的web服务的本地主机url调用了该服务。当我在localhost上运行我的网站时,这个url是有效的。当我将我的网站上传到托管服务器时,我已将url更改为http://somedomain.com/Service.svc/Read问题是WCF服务只能在我的本地主机上调用,但不能在托管服务器上调用。我在本地主机上运行网站时测试了该服务;它是成功的,并且对象正常返回,但不在托管服务器上。

最后,我的问题是如何在web.config文件中配置托管服务器上的WCF服务。

我希望我的示例代码能让你清楚地了解我的问题。我正处于问题的边缘,需要stackoverflow社区的一些帮助。请帮我一下。

为了从javascript访问WCF服务,它应该是RESTful服务。因此,尝试使WCF成为RESTful服务。可以参考http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide

这是我的问题的答案。以下文档仅适用于Visual Studio 2008、ASP.NET Webiste使用C#生成的WCF服务。

服务名称:服务

问题主要来自web.config文件的配置。让我们在web.config文件中清楚地了解WCF服务的配置。

这是web.config中system.serviceModel标记的内容,该标记由Visual Studio 2008在创建WCF服务时生成。

<configuration>
<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <behaviors>
      <endpointBehaviors>
        <behavior name="ServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Service">
        <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
          binding="webHttpBinding" contract="Service" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

正如您所看到的,服务标签具有属性名称"service"。行为名称为"ServiceAspNetAjaxBehavior"。在服务端点标记中,有两个属性"biding"answers"contract"的值分别为"webHttpBinding"answers"Service"。当Visual Studio 2008生成WCF服务时,这些设置将自动应用于web.config文件。

现在,Visual Studio 2008中的所有设置都准备好让Web服务在托管服务器上运行了吗?答案是,我们必须做更多的任务才能使服务投入使用。我们接下来要做的是重构system.serviceModel标记的内容。

因为服务端点标记中的地址属性为空,所以当我们输入服务的地址时,它会显示错误消息"您无权查看此目录…">。服务器不知道服务的地址,所以当客户端输入服务的物理地址时,它不允许任何访问。

1.设置服务地址

通过设置服务地址的地址,我将放置更多的标签。首先,我将把我的网站服务地址添加到端点标签的地址属性中:

<endpoint address="http://mydomainname.com/Service.svc" behaviorConfiguration="ServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="Service" />

我还将服务地址添加到serviceHostingEnvironment标签中:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
          <baseAddressPrefixFilters>
              <add prefix="http://mydomainname.com"/>
          </baseAddressPrefixFilters>
    </serviceHostingEnvironment>

注意:地址只是"baseAddressPrefixFilters"标签中"add"标签前缀内的基本域名

好的,现在服务地址可以了。我将移到服务行为旁边。只有端点的行为,但没有服务的行为。我需要添加一个服务行为。

2.设置服务行为

在行为标签中,我将添加名为"MyServiceTypeBehaviors"的服务行为:

<behaviors>
      <serviceBehaviors>
        <behavior name="MyServiceTypeBehaviors">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="ServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>

现在,我有了服务的行为名称"MyServiceTypeBehaviors",并将其添加到服务内部服务标签的属性"behaviorConfiguration"中:

<service name="Service" behaviorConfiguration="MyServiceTypeBehaviors">
        <endpoint address="http://mydomainname.com/Service.svc" behaviorConfiguration="ServiceAspNetAjaxBehavior"
          binding="webHttpBinding" contract="Service" />
      </service>

3.查看"system.serviceModel"标签的结构

最后,WCF服务的配置已准备好在托管服务器上运行。让我们再次查看web.config中system.serviceModel标记的内容:

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
          <baseAddressPrefixFilters>
              <add prefix="http://mydomainname.com"/>
          </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyServiceTypeBehaviors">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="ServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name="Service" behaviorConfiguration="MyServiceTypeBehaviors">
        <endpoint address="http://mydomainname.com/Service.svc" behaviorConfiguration="ServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="Service" />
      </service>
    </services>
  </system.serviceModel>

当我们从托管服务器输入服务地址时,如果它显示一条消息"您已经创建了一个服务。">则我们的任务完成,服务即可使用。如果没有,我们会再次查看服务地址,它们是否正确或某些行为名称不正确等……但我相信我们最终会发现问题并亲手解决。为了我的网站的安全,我将删除包含我的示例代码文件的整个超链接,并更改我真实网站的域名。

我希望我的问题能帮助到任何在我的问题上有同样问题的人。

我有点感谢stackoverflow社区和任何帮助我的人。

这只是@tri-nuyen-dung最后一条评论的附加组件,我用它让我的服务在托管服务器(arvixe(上的虚拟目录中工作。

这是我对他的Web.config部分的版本,它位于'wwwroot'<virtualdirectory>'Web.config:中

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="<virtualdirectory>Behaviour" >
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="<virtualdirectory>Behaviour">
                <enableWebScript />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" minFreeMemoryPercentageToActivateService="0">
        <baseAddressPrefixFilters>
            <add prefix="http://<yourserver>.com"/>
        </baseAddressPrefixFilters>             
    </serviceHostingEnvironment>
    <services>
        <service name="<virtualdirectory>.Services.<virtualdirectory>Service" behaviorConfiguration="<virtualdirectory>Behaviour">
            <host>
                <baseAddresses>
                    <add baseAddress="http://<yourserver>.com"/>
                </baseAddresses>
            </host>
            <endpoint address="http://<yourserver>.com/<virtualdirectory>/Services/<virtualdirectory>Service.svc"
                    behaviorConfiguration="EDGEBehaviour"
                    binding="webHttpBinding"
                    contract="virtualdirectory.Services.I<virtualdirectory>Service" />
        </service>
    </services>
</system.serviceModel>

<yourserver><virtualdirectory>是您的应用程序地址;为了获得您的例如服务帮助页面,我的地址是http://<yourserver>.com/<virtualdirectory>/Services/<virtualdirectory>Service.svc/help。你不必为你的应用程序代码使用我的命名约定,但它对我有效。

这是我的I<virtualdirectory>Service.cs代码:

namespace <virtualdirectory>.Services
{
    [ServiceContract]
    public interface I<virtualdirectory>Service
    {
        [OperationContract]
        object GetFormResult(string form_id);

以下是实现(<virtualdirectory>Service.svc.cs(:

namespace <virtualdirectory>.Services
{
    using <lots>;
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class <virtualdirectory>Service : I<virtualdirectory>Service 
    {
        [WebGet(UriTemplate = "GetFormResult?form_id={form_id}", ResponseFormat = WebMessageFormat.Json)]
        public object GetFormResult(string form_id)
        {

实现标记(<virtualdirectory>Service.svc(:

<%@ ServiceHost Language="C#" Debug="true" Service="<virtualdirectory>.Services.<virtualdirectory>Service" Factory="<virtualdirectory>.WebServiceHostFactory3WithJsonP" CodeBehind="<virtualdirectory>Service.svc.cs" %>

请注意,我从谷歌某处获得了WebServiceHostFactory3WithJsonP,用于通过WCF提供REST+JSON。.NET 4.5中较新的WebAPI更好,但我的网站是在.NET 4中。

为了完整起见,下面是我的javascript调用:

jQuery(document).ready(function ($) {
    jQuery('#formdetails').submit(function () {
    jQuery('.widget_formdetails input[type="submit"]').hide();
    jQuery('.formloading').show();
    var form_parameters = jQuery(this).serialize();
    var form_type = jQuery('#form_type').val();
    switch (form_type) {
        case '<someoption>':
        var js<someoption> = new f<someoption>(  // object helper function
                    jQuery('#textfield1').val(), 
                    jQuery('#textfield2').val(), 
                    jQuery('#textfield3').val()
                    );
        var json<someoption> = JSON.stringify({ Message: js<someoption>});
        $.getJSON(
            '/<virtualdirectory>/Services/<<virtualdirectory>Service.svc/GetFormResult',
            'form_request=' + json<someoption>,
            form_request // callback function
        );
        break;