使用 Azure 应用服务托管的 WCF 服务出错:HTTP 错误 405.0 - 方法不允许

Error in WCF service hosted with Azure app service: HTTP Error 405.0 - Method Not Allowed

好的,完全是 WCF 新手,所以请耐心等待。

我在 Azure 应用服务上发布了一个 WCF Web 服务,以及一个必须连接到该服务的 Xamarin.forms 应用程序。

我创建了 WCF 服务,起初我尝试自行托管它,然后使用 visual studio 2017 "Add service" 在我的 xamarin 应用程序上创建了客户端。所以它添加了 Reference.cs 文件,我制作了代理 class 和接口来连接到服务等等。

我在从手机连接到服务时遇到问题,所以我在 Azure 应用程序服务上发布了该服务(毕竟它是免费的),启用了 Azure 日志,修改了 NLog.config 文件以登录到跟踪,只修改了我的移动应用程序中的 URL,现在每次我尝试从我的手机连接到它时服务都会抛出这个:

HTTP 错误 405.0 - 方法不正确 Allowed.The 由于使用了无效的方法(HTTP 谓词),无法显示您要查找的页面。

我正在 Visual Studio 的 LogFiles\DetailedErrors 文件夹中的 Cloud Explorer 中读取错误。

老实说,我对HTTP几乎一无所知,但我知道我没有在服务中写过HTTP。我想 WCF 使用它并且在某个时刻,在某个地方使用了一个错误的动词,但我应该如何知道在哪里更改它甚至如何检查它?我刚刚制作了一个接口,一个 class,并调用了 class 上的方法...不知道在哪里寻找 POST 或 GET。

无论如何,我什至不确定我应该在此处 post 使用什么代码,但我已经阅读了大量关于此的问题,所以这里是其中的一些:

服务class

public class MJRFFrasCdadesService : IMJRFFrasCdadesService, IDisposable
{
    private Users.UsersClass _Users = new Users.UsersClass();
    private static NLog.Logger _Logger = NLog.LogManager.GetCurrentClassLogger();
    private bool _Disposed;

    public static event EventHandler<ConnectionEventArgs> ConnectionEvent;
    public static event EventHandler<ConnectionEventArgs> DisconnectionEvent;

    public string Ping()
    {
        return "Ok";
    }

    public async Task<string> GoogleLoginAsync(string email)
    {
        NLog.LogManager.Configuration.Variables["email"] = "";
        _Logger.Info("{1}{2}{1}           Comienza google login con email: {0}{1}{2}",
            email,
            Environment.NewLine,
            "-----------------------------------*******************************************");

        var driveHandler = await _Users.NewUserAsync(email);

        try
        {
            var init = await driveHandler.InitDriveAsync(email);
            _Logger.Info("InitDriveAsync finalizado con resultado: {0}", init);
            if (!init || !driveHandler.LoginOK)
            {
                _Logger.Info("Devolviendo mensaje de error: {0}", driveHandler.MsgError);
                return driveHandler.MsgError;
            }
            _Logger.Info("Login ok, devolviendo \"Ok\"");
            return "Ok";
        }
        catch (Exception e)
        {
            _Logger.Error(e);
            return e.ExceptionErrorMessage();
        }
    }

    public async Task<string> UploadFileAsync(byte[] fileBytes, string fileName, string email)
    {
        _Logger.Info("Comienza subida de fichero con nombre {0}", fileName);

        var driveHandler = await _Users.GetUserDriveHandler(email);
        if (driveHandler == null)
        {
            _Logger.Info("No logueado. Devolviendo \"User not logged\"");
            return "User not logged";
        }

        try
        {
            if (!driveHandler.LoginOK)
            {
                _Logger.Info("No logueado. Devolviendo \"Not logged\"");
                return "Not logged";
            }

            var result = await driveHandler.UploadImageAsync(fileBytes, fileName);
            _Logger.Info("Proceso de subida terminado. Resultado: {0}", result);
            if (!result)
            {
                _Logger.Info("Devolviendo mensaje de error: {0}", driveHandler.MsgError);
                return driveHandler.MsgError;
            }
            _Logger.Info("Subida ok, devolviendo \"Ok\"");
            return "OK";
        }
        catch (Exception e)
        {
            _Logger.Error(e);
            return e.ExceptionErrorMessage();
        }
    }

    public void Dispose()
    {
        if (!_Disposed)
        {
            _Users.Dispose();
        }
        _Disposed = true;
    }

    public void FirstMethod()
    {
        if (ConnectionEvent != null)
        {
            string m = "Alguien se ha conectado";
            ConnectionEvent(null, new ConnectionEventArgs()
            {
                Message = m
            });
            _Logger.Info(m);
        }
    }

    public void LastMethod()
    {
        if (DisconnectionEvent != null)
        {
            string m = "Alguien se ha desconectado";
            DisconnectionEvent(null, new ConnectionEventArgs()
            {
                Message = m
            });
            _Logger.Info(m);
        }
    }
}

界面

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IMJRFFrasCdadesService
{
    [OperationContract]
    string Ping();

    [OperationContract]
    Task<string> GoogleLoginAsync(string email);

    [OperationContract]
    Task<string> UploadFileAsync(byte[] fileBytes, string fileName, string email);

    [OperationContract(IsInitiating = true)]
    void FirstMethod();

    [OperationContract(IsTerminating = true)]
    void LastMethod();
}

Web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.7.1" />
    <httpRuntime targetFramework="4.7.1"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- Para evitar revelar información de los metadatos, establezca los valores siguientes en false antes de la implementación  -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- Para recibir detalles de las excepciones en los fallos, con el fin de poder realizar la depuración, establezca el valor         siguiente en true. Para no revelar información sobre las excepciones, establézcalo en false antes de la implementación -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        Para examinar el directorio raíz de la aplicación web durante la depuración, establezca el valor siguiente en true.
        Establézcalo en false antes de la implementación para evitar revelar información sobre la carpeta de aplicación web.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

也就是。

基本上,我花了一个多星期的时间来学习和尝试做这件事,现在我非常沮丧,我不知道发生了什么,所以 ANY 帮助将不胜感激,包括一个简单的 "hey you know nothing! you must read this <include here link I shoud read>!".


编辑: 好的,由于 Mahlatse 的指示,我已经尝试了两种方法。

在我尝试通过 https://mjrffacturascomunidadeswebservice.azurewebsites.net/ 访问服务之前,出现一条消息说 Your App Service app is up and running,所以我认为一切正常,但是当我尝试将 svc 文件附加到那个 URL,它抛出了关于请求会话但使用不支持会话的 basicHTTPbinding 的异常。

我删除了接口属性 [ServiceContract(SessionMode = SessionMode.Required)] 中的会话模式参数以及 FirstMethodLastMethod 方法,异常消失了。现在,如果浏览到 https://mjrffacturascomunidadeswebservice.azurewebsites.net/MJRFFrasCdadesService.svc ,它会显示 You have created a service. 而不是,所以我想现在它真的启动了 运行... 所以我尝试在我的应用程序中测试它并抛出这个:

            Error: 
There was an error on processing web request: Status code 405(MethodNotAllowed): Method Not Allowed ;

            Trace: 
at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_remoting_wrapper(intptr,intptr)
at (wrapper remoting-invoke) ServiceReference1.IMJRFFrasCdadesService.GoogleLoginAsync(string)
at ServiceReference1.MJRFFrasCdadesServiceClient.GoogleLoginAsync (System.String email) [0x00006] in <61e2d5b4688b450c9b2865fbef0c9da1>:0 
at MJRFFacturasComunidades.Model.WebService.WebServiceClass+<LogEmail>d__6.MoveNext () [0x00023] in <61e2d5b4688b450c9b2865fbef0c9da1>:0 ;

这是一个不同的错误(我想至少这是一个进步)。如您所见,方法 GoogleLoginAsync 正在抛出该异常,但现在抛出它的是我的应用程序方法,而不是服务:ServiceReference1.MJRFFrasCdadesServiceClient 是由 Visual Studio 生成的 class当我还在自己托管服务时添加服务引用时。

我想我要删除那个引用,向 azure 中托管的服务添加一个新引用,然后再次测试所有这些。


编辑2:

是的,它解决了那个问题,但现在我有了这个:

Error in deserializing body of request message for operation 'GoogleLogin'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GoogleLogin' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GoogleLoginAsync' and namespace 'http://tempuri.org/' ;

            Trace: 
at (wrapper managed-to-native) System.Object.__icall_wrapper_mono_remoting_wrapper(intptr,intptr)
at (wrapper remoting-invoke) ServiceReference2.IMJRFFrasCdadesService.GoogleLoginAsync(string)
at ServiceReference2.MJRFFrasCdadesServiceClient.GoogleLoginAsync (System.String email) [0x00006] in <e1f3df4dfbf340f09d2768d7fbc33427>:0 
at MJRFFacturasComunidades.Model.WebService.WebServiceClass+<LogEmail>d__6.MoveNext () [0x00023] in <e1f3df4dfbf340f09d2768d7fbc33427>:0  ;

xD 一个接着一个。好的,我不确定我是否应该在同一个问题中继续问这个问题,因为原来的问题已经解决了,所以我接受答案并继续尝试或打开一个新问题。

以下是您可以尝试的一些方法

  1. 检查服务是否 运行(浏览到 .svc 文件应该就足够了)
  2. 检查服务契约是否相同,这将是 WSDL 文件(检查所有方法是否相同(更重要的是您的方法是否存在)