Azure Web 应用程序与 Azure VM 上的 windows 表单应用程序之间的通信

Communication between an Azure web application and a windows form app on Azure VM

这是我使用 Azure 的第一个项目。所以如果我问的是非常基础的问题,请耐心等待。

我有一个在 Azure 服务器上运行的 Web 应用程序。我还有一个托管在 Azure VM 上的 windows 表单应用程序。根据要求,Web 应用程序会在需要时与 windows 表单应用程序建立连接,向表单应用程序发送通知,收到响应并切断连接。所以这里的 Web 应用程序就像一个客户端,Windows 表单应用程序就像一个服务器。

我尝试使用 SignalR。在 Azure 门户上激活 Windows 表单应用程序的端点和端口。我能够建立连接,但从未从 Windows 表单应用程序

获得连接确认

我使用的是正确的技术还是有更好的方法来做到这一点?我希望有人能提出一个合适的解决方案。

这是我试过的

Windows 表单应用程序中的服务器端代码

  1. 通过 Nuget 安装了 Microsoft.AspNet.SignalR 包

  2. 从 Azure 门户激活了 VM 端点和端口 #12345

  3. VM 的 DNS 名称 - abc.xyz.net

  4. 端点端口号 - 12345

    public partial class FormsServer : Form
    {
    private IDisposable SignalR { get; set; }
    const string ServerURI = "http://abc.xyz.net:12345";
    private void btnStart_Click(object sender, EventArgs e)
    {            
        btnStart.Enabled = false;
        Task.Run(() => StartServer());
    }
    private void StartServer()
    {
        try
        {
            SignalR = WebApp.Start<Startup>(ServerURI);
        }
        catch (TargetInvocationException)
        { }            
    }
    

    }

    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);
            app.MapSignalR("/CalcHub", new HubConfiguration());
    }       
    

    }

    public class CalcHub : Hub
      {            
    public async Task<int> AddNumbers(int no1, int no2)
    {
        MessageBox.Show("Add Numbers");
        return no1 + no2;
    }        
    }
    

Web 应用程序中的客户端代码

  1. 通过 Nuget 安装了 Microsoft.AspNet.SignalR.Client

    public class NotificationAppClient
    {
    Microsoft.AspNet.SignalR.Client.HubConnection connectionFr;
    IHubProxy userHubProxy;
    public void InitiateServerConnection()
    {
        connectionFr = new Microsoft.AspNet.SignalR.Client.HubConnection("http:// abc.xyz.net:12345/CalcHub", useDefaultUrl: false);
        connectionFr.TransportConnectTimeout = new TimeSpan(0, 0, 60);
        connectionFr.DeadlockErrorTimeout = new TimeSpan(0, 0, 60);
        userHubProxy = connectionFr.CreateHubProxy("CalcHub");
    
        userHubProxy.On<string>("addMessage", param => {
            Console.WriteLine(param);
        });
    
        connectionFr.Error += async (error) =>
        {
            await Task.Delay(new Random().Next(0, 5) * 1000);
            await connectionFr.Start();
        };
    }
    
    public async Task<int> AddNumbers()
    {
        try
        {
            int result = -1;
            connectionFr.Start().Wait(30000);
            if (connectionFr.State == ConnectionState.Connecting)
            {
                connectionFr.Stop();
            }
            else
            {
                int num1 = 2;
                int num2 = 3;
                result = await userHubProxy.Invoke<int>("AddNumbers", num1, num2);
            }
            connectionFr.Stop();
            return result;
        }
        catch (Exception ex)
        { }
        return 0;
    }
    

    }

其实没有必要不停地连接和断开。持久连接也将起作用。

感谢回复

所以代码即使乱七八糟也能正常工作。通常这是一个防火墙问题,所以我会绝对确保端口在两个服务之间一直打开。检查 Windows 防火墙和 Azure 网络安全组中的防火墙以确保端口已打开。我建议仔细检查 "Effective Security Rules"。如果有多个安全组在起作用,很容易在一个组中打开端口而忘记另一个。

为了排除 DNS 问题,您可以将 const string ServerURI = "http://abc.xyz.net:12345"; 更改为 `"http://*:12345" 并尝试通过 public IP 连接。

最后,如果 catch 块实际上是空的,而不是仅仅缩短代码,请将其删除或添加一些内容以让您看到错误。就像任何错误都被吞没一样,不知道它们是否正在发生。我没有收到任何 运行 你的代码,但最好确定一下。


就通信方法而言,如果您要坚持使用 SignalR,我会将客户端上的连接打开到 InitiateServerConnection() 并在客户端处于活动状态时保持打开状态。这是 hoq SignalR 旨在工作,而不是每次打开和关闭连接。如果您的最终目标是将信息从您的表单应用程序实时推送到网络应用程序,而不是网络应用程序提取数据,这很好。对于您目前正在做的事情,这并不理想。

对于这种用例,我强烈建议查看 WebAPI 而不是 SignalR。如果您要添加更多端点,与 WebApi 相比,SignalR 将变得越来越难以使用。如果您需要将数据推送到 Web 客户端,但又希望能够按需请求信息,则完全可以同时使用两者。

服务器上的 Startup 方法略有变化,因为正在设置的是 Microsoft.AspNet.WebApi 而不是 SignalR:

class Startup
{
    public void Configuration(IAppBuilder app)
    {

        HttpConfiguration config = new HttpConfiguration();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        app.UseCors(CorsOptions.AllowAll);
        app.UseWebApi(config);
    }
}

您创建控制器而不是集线器。

public class AddController : ApiController
{

    // GET api/add?num1=1&num2=2
    public HttpResponseMessage Get(int num1, int num2)
    {
        var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
        response.Content = new StringContent((num1 + num2).ToString());

        return response;
    }
}

客户端是事情变得简单得多的地方,因为您不再需要管理通常是持久连接的东西。 InitiateServerConnection() 可以完全消失。 AddNumbers() 变成一个简单的 http 调用:

public static async Task<int> AddNumbers(int num1, int num2)
{
    try
    {
        using(var client = new HttpClient())
        {
            return Int32.Parse(await client.GetStringAsync($"http://<sitename>:12345/api/add?num1={num1}&num2={num2}"));
        }
    }
    catch (Exception e)
    {
        //Do something with the exception
    }

    return 0;
}

如果这不能最终解决问题,请告诉我,我们可以继续进行故障排除。