WCF Restful Web服务端点已公开,但所有方法都返回http 404 not found c#

WCF Restful Web服务端点已公开,但所有方法都返回http 404 not found c#,c#,asp.net,web-services,wcf,https,C#,Asp.net,Web Services,Wcf,Https,我已经编写了我的第一个Web服务,当我在本地开发机器上从VisualStudio测试运行它时,一切都按预期工作。我去客户端部署服务,发现部署后我可以到达端点,但我的所有方法都返回HTTP404NotFound Web服务在VisualStudio中使用WCF编写,并设置为返回Json。Web服务的目标是.Net framework 4.5。该站点配置为HTTPS协议,并具有有效的SSL证书。我已使用最新版本的.Net framework 4.5更新服务器,并相应地将应用程序池应用于该站点 当我从

我已经编写了我的第一个Web服务,当我在本地开发机器上从VisualStudio测试运行它时,一切都按预期工作。我去客户端部署服务,发现部署后我可以到达端点,但我的所有方法都返回HTTP404NotFound

Web服务在VisualStudio中使用WCF编写,并设置为返回Json。Web服务的目标是.Net framework 4.5。该站点配置为HTTPS协议,并具有有效的SSL证书。我已使用最新版本的.Net framework 4.5更新服务器,并相应地将应用程序池应用于该站点

当我从外部浏览器转到客户端服务器上的端点位置时(我已修改屏幕截图和链接以删除真实域):

链接如下所示:

我得到的页面显示了指向WSDL和SingleWSDL页面的Web服务链接,它们正确地显示了端点方法和各种其他配置信息

在我看来,一切都如预期的那样,我有点不确定下一步该去哪里寻找问题

现在我很不确定Web.config文件的要求是什么。下面是Web服务的当前Web.config文件。可能是我在这里遗漏了有关服务部署的重要信息,但我想知道为什么服务会在VisualStudio中成功运行?唯一值得注意的区别是,我在VisualStudio中使用http而不是https运行服务

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <connectionStrings>
    <add name="BAXISQL"
         connectionString="Database=SomeDatabase;Server=SomeServer;User ID=user;Password=password"
         providerName="System.Data.SqlClient"
    />
  </connectionStrings>
  <system.serviceModel>
    <services>
      <service name="WorksWebService.WorksWebService">
        <endpoint address="" behaviorConfiguration="restful" binding="webHttpBinding"
          contract="WorksWebService.IWorksWebService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="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 name="restful">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
  <startup>
    <supportedRuntime version="4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>
下面是WebService.svc.cs文件中相应的方法调用(也修改为仅显示单个方法):

使用系统;
使用System.Collections.Generic;
使用系统集合;
使用System.Data.SqlClient;
Net系统;
使用System.ServiceModel.Web;
使用System.Web;
使用Newtonsoft.Json;
使用System.Runtime.Serialization;
使用System.IO;
使用System.ServiceModel;
使用系统文本;
使用Newtonsoft.Json.Linq;
命名空间工作Web服务
{
公共类WorkWebService:IWorksWebService
{
//所有方法必须在标头中接收的键,以验证请求是否来自有效源
专用字符串baxiSMSKey=“C5A75B32-5BC9-4D89-AB78-F8FE0CF58806”;
//BAXI_SMS_键:C5A75B32-5BC9-4D89-AB78-F8FE0CF58806
#区域训练状态
//测试url字符串
//WorksWebService.svc/rest/member/C211292/trainingstatus?国家/地区=GB
/// 
///方法查找特定客户的培训状态日期
/// 
/// 
/// 
///上次有效培训状态日期或客户将参加培训的未来日期
[WebInvoke(Method=“GET”,ResponseFormat=WebMessageFormat.Json
,UriTemplate=“rest/member/{urn}/trainingstatus?pastdays={pastdays}&futuredays={futuredays}”)]
公共字符串GetTrainingStatus(字符串urn、字符串pastdays、字符串futuredays)
{
string dateString=string.Empty;
WebOperationContext上下文=WebOperationContext.Current;
//检查BAXI_SMS_密钥的标题
if(CheckAPIKey())
{
//验证url参数
if(ValidateURLStringParameters_GetTrainingStatus(urn、过去、未来))
{
//查找培训状态
dateString=GetTrainingDate(urn、过去日期、未来日期);
if(dateString.Contains(“错误:))
context.OutgoingResponse.StatusCode=HttpStatusCode.InternalServerError;//HTTP代码500
else if(dateString.Equals(string.Empty))
context.OutgoingResponse.StatusCode=HttpStatusCode.NotFound;//HTTP代码404
其他的
context.OutgoingResponse.StatusCode=HttpStatusCode.OK;//HTTP代码200
}
其他的
context.OutgoingResponse.StatusCode=HttpStatusCode.BadRequest;//HTTP代码400
}
其他的
context.OutgoingResponse.StatusCode=HttpStatusCode.probled;//HTTP代码403
返回日期字符串;
}
/// 
///方法验证GetTrainingStatus Web方法的参数
/// 
/// 
/// 
/// 
///真假
私有bool ValidateURLStringParameters\u GetTrainingStatus(字符串urn、字符串PasstDays、字符串futuredays)
{
if(string.IsNullOrWhiteSpace(urn))
返回false;
if(string.IsNullOrWhiteSpace(过去天))
返回false;
if(string.IsNullOrWhiteSpace(futuredays))
返回false;
尝试
{
转换为32(过去天);
转换为32(未来天数);
}
捕获(例外e)
{
返回false;
}
返回true;
}
/// 
///方法查找成员的培训状态
/// 
/// 
///过去或将来的用户培训日期
私有字符串GetTrainingDate(字符串urn、字符串pastdays、字符串futuredays)
{
string dateSt=string.Empty;
尝试
{
//针对客户的首次搜索
var connection=new-SqlConnection(System.Configuration.ConfigurationManager.ConnectionString[“BAXISQL”].ConnectionString);
connection.Open();
var sqlCommand=connection.CreateCommand();
sqlCommand.CommandText=“选择dbo.WORKS\u GetTrainingDate\u fn(@URN、@pass、@Future)”;
sqlCommand.Parameters.AddWithValue(“@URN”,URN);
sqlCommand.Parameters.AddWithValue(“@pass”,p
using System.IO;
using System.ServiceModel;
using System.Web.Services;

namespace WorksWebService
{
    [ServiceContract]
    interface IWorksWebService
    {
        [OperationContract]
        [WebMethod]
        string GetTrainingStatus(string urn, string pastdays, string futuredays);   
    }
}
using System;
using System.Collections.Generic;
using System.Collections;
using System.Data.SqlClient;
using System.Net;
using System.ServiceModel.Web;
using System.Web;
using Newtonsoft.Json;
using System.Runtime.Serialization;
using System.IO;
using System.ServiceModel;
using System.Text;
using Newtonsoft.Json.Linq;

namespace WorksWebService
{
    public class WorksWebService: IWorksWebService
    {
        // key that all methods must receive in the header to validate that the request is from a valid source
        private string baxiSMSKey = "C5A75B32-5BC9-4D89-AB78-F8FE0CF58806";
        //BAXI_SMS_KEY: C5A75B32-5BC9-4D89-AB78-F8FE0CF58806

        #region TrainingStatus

        // test url string
        // WorksWebService.svc/rest/member/C211292/trainingstatus?country=GB
        /// <summary>
        /// Method to find the training status dates for a specific Customer
        /// </summary>
        /// <param name="urn"></param>
        /// <param name="country"></param>
        /// <returns>Last valid training status date or future date the customer will be attending training</returns>
        [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json
            , UriTemplate = "rest/member/{urn}/trainingstatus?pastdays={pastdays}&futuredays={futuredays}")]
        public string GetTrainingStatus(string urn, string pastdays, string futuredays)
        {
            string dateString = string.Empty;
            WebOperationContext context = WebOperationContext.Current;
            // check the headers for the BAXI_SMS_KEY
            if (CheckAPIKey())
            {
                // validate the url parameters
                if (ValidateURLStringParameters_GetTrainingStatus(urn, pastdays, futuredays))
                {
                    // find the training status
                    dateString = GetTrainingDate(urn, pastdays, futuredays);

                    if (dateString.Contains("Error: "))
                        context.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError; // HTTP Code 500
                    else if (dateString.Equals(string.Empty))
                        context.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; // HTTP Code 404
                    else
                        context.OutgoingResponse.StatusCode = HttpStatusCode.OK; // HTTP Code 200
                }
                else
                    context.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest; // HTTP Code 400
            }
            else
                context.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden; // HTTP Code 403

            return dateString;
        }

        /// <summary>
        /// method to validate the parameters for GetTrainingStatus Web method
        /// </summary>
        /// <param name="urn"></param>
        /// <param name="pastdays"></param>
        /// <param name="futuredays"></param>
        /// <returns>True or False</returns>
        private bool ValidateURLStringParameters_GetTrainingStatus(string urn, string pastdays, string futuredays)
        {
            if (string.IsNullOrWhiteSpace(urn))
                return false;

            if (string.IsNullOrWhiteSpace(pastdays))
                return false;

            if (string.IsNullOrWhiteSpace(futuredays))
                return false;

            try
            {
                Convert.ToInt32(pastdays);
                Convert.ToInt32(futuredays);
            }
            catch (Exception e)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Method to find the training status of the member
        /// </summary>
        /// <param name="urn"></param>
        /// <returns>the date of the users training past of future</returns>
        private string GetTrainingDate(string urn, string pastdays, string futuredays)
        {
            string dateSt = string.Empty;
            try
            {
                // first search against customers
                var connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["BAXISQL"].ConnectionString);
                connection.Open();
                var sqlCommand = connection.CreateCommand();
                sqlCommand.CommandText = "SELECT dbo.WORKS_GetTrainingDate_fn(@URN, @Past, @Future)";
                sqlCommand.Parameters.AddWithValue("@URN", urn);
                sqlCommand.Parameters.AddWithValue("@Past", pastdays);
                sqlCommand.Parameters.AddWithValue("@Future", futuredays);

                string date = sqlCommand.ExecuteScalar().ToString();
                connection.Close();

                if (!string.IsNullOrWhiteSpace(date))
                {                    
                    string[] parts = date.ToString().Split('/');
                    dateSt = parts[2] + parts[1] + parts[0];
                }
            }
            catch (Exception e)
            {
                dateSt = "Error: " + e.Message + "<br />Source: " + e.Source + "<br />Stacktrace: " + e.StackTrace;
            }

            return dateSt;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Method to determine if the API key has been passed in succesfully
        /// </summary>
        /// <returns>true or false</returns>
        private bool CheckAPIKey()
        {
            bool matchedKey = false;
            IncomingWebRequestContext request = WebOperationContext.Current.IncomingRequest;
            WebHeaderCollection headers = request.Headers;

            System.Diagnostics.Debug.Write("\r\n-------------------------------------------------------");
            System.Diagnostics.Debug.Write("\r\n" + request.Method + " " + request.UriTemplateMatch.RequestUri.AbsolutePath);
            foreach (string headerName in headers.AllKeys)
            {
                System.Diagnostics.Debug.Write("\r\n" + headerName + ": " + headers[headerName]);
                if (headerName.Equals("BAXI_SMS_KEY"))
                {
                    if (baxiSMSKey.ToString().ToUpper().Equals(headers[headerName]))
                    {
                        matchedKey = true;
                    }
                }
            }
            System.Diagnostics.Debug.Write("\r\n-------------------------------------------------------");

            return matchedKey;
        }

        #endregion

    }
}
<services>
  <service name="WorksWebService.WorksWebService">
    <endpoint address="" behaviorConfiguration="restful" binding="webHttpBinding" bindingConfiguration="HttpBinding"
      contract="WorksWebService.IWorksWebService" />
    <endpoint address="" behaviorConfiguration="restful" binding="webHttpBinding" bindingConfiguration="HttpsBinding"
      contract="WorksWebService.IWorksWebService" />
  </service>
</services>
<bindings>
  <webHttpBinding>
    <binding name="HttpBinding">
      <security mode="None">
        <transport clientCredentialType="None"/>
      </security>
    </binding>
    <binding name="HttpsBinding">
      <security mode="Transport">
        <transport clientCredentialType="None"/>
      </security>
    </binding>
  </webHttpBinding>
</bindings>
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <connectionStrings>
    <add name="BAXISQL" connectionString="Database=SomeDatabase;Server=SomeServer;User ID=User;Password=Password" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.serviceModel>
    <services>
      <service name="WorksWebService.WorksWebService">
        <endpoint address="" behaviorConfiguration="restful" binding="webHttpBinding" bindingConfiguration="HttpBinding"
          contract="WorksWebService.IWorksWebService" />
        <endpoint address="" behaviorConfiguration="restful" binding="webHttpBinding" bindingConfiguration="HttpsBinding"
          contract="WorksWebService.IWorksWebService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="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="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="restful">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <bindings>
      <webHttpBinding>
        <binding name="HttpBinding">
          <security mode="None">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
        <binding name="HttpsBinding">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
  <startup>
    <supportedRuntime version="4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>