引言

     有段时间没有写博客了,不知道写什么,加上最近一直在玩单片机方面的东西,所以有一些懈怠。首先呢,为什么会有这么一个问题,是在一个QQ群里,有看到有人提问,能不能在启动Winform的同时去启动一个Web服务器去监听请求然后去做相应的业务处理,同时也可能存在和Winform之间的交互,然后也闲来无事,就动手实现了一下。

实现方式

     在传统的Winform程序中,我们在程序中嵌套一个Webapi后端服务器的手段,是可以借助HttpListener去实现监听某一个指定的Url地址,使用BeginGetContext方法或者GetContext方法可以获取到我们请求的HttpListenerContext的上下文对象,里面包含了我们请求的信息,以及后续要写入的Response信息,从而实现一个Webapi的手段;不排除有人手撕socket自己在socket的基础上封装一个。

     不过提这个问题的我倒没有看他是否要求是fw版本还是net6,所以我在Net6的基础上实现了一个,我们都知道,不管是Winform程序还是net6的Web程序,都是有一个Program类去启动程序或者Web程序,这两个,所依赖的SDK还有程序配置的默认的目标框架不一样,也就是TargetFramework,所以在Net6 Winform程序中,默认是无法使用Web相关的类以及接口的,同时就算是自己引入包也无法解决此问题,因为在5之后,Netstandard类库都转移统一版本net5或者6的一个大一统环境,所以自己去Nuget引入这些包也是不得解决。

     解决方案其实也很简单,双击项目文件,编辑项目文件csproj,在最上方修改sdk为两个sdk都加上,这样也不会存在什么问题,同时TargetFrameworks设置为windows和net6.0,设置目标框架。同时还需要设置下面的TargetPlatformIdentifier为WINDOWS否则会报错提示,以及需要设置 UseWindowsForms,设置使用Winform,即可在Winform中启动一个Net6的WebApi程序,至于页面我没有测试,不过应该也开始可以的Program整体代码如下

 

 

<Project Sdk="Microsoft.NET.Sdk;Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
      <TargetFrameworks>net6.0-Windows;net6.0</TargetFrameworks>
      <TargetPlatformIdentifier>WINDOWS</TargetPlatformIdentifier>
    <Nullable>enable</Nullable>
    <UseWindowsForms>True</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <StartupObject>Test.Program</StartupObject>
    <EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
  </PropertyGroup>

  <ItemGroup>
    <None Include="..\.editorconfig" Link=".editorconfig" />
  </ItemGroup>

</Project>

 

Program 

     中间开启线程去启动Web程序,指定启动的地址,以及设置启动类,这些都可以根据自己的要求去设置

 internal static class Program
    {
        public static Form1 Form1 { get; set; }
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
#if WINDOWS
            ApplicationConfiguration.Initialize();
#endif
            Task.Run(() => {
                Host.CreateDefaultBuilder(null)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseUrls("http://127.0.0.1:8989/");
                    webBuilder.UseStartup<Startup>();
                }).Start();
            });
#if WINDOWS
            Form1 = new Form1();
            Application.Run(Form1);
#endif
        }
    }

 

Startup

    Startup文件就和之前net5的是一样的没有任何改动,对于Url映射什么也都没问题,如果需要和某个窗体做交互,建议在此处可以将所有的窗体注入进去,然后在对应的Controller去做交互即可,不同的界面不同的生命周期,但是必须和Winform窗体中,所要显示的是同一个对象。

 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(Program.Form1);
            services.AddControllers();
            services.AddRouting();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app)
        {
            //app.Use(s => {
            //    return b =>
            //    {
            //        var n = Encoding.UTF8.GetBytes("12321321");
            //        return b.Response.Body.WriteAsync(n,0,n.Length);
            //    };
            //});
            app.UseRouting();
            app.UseEndpoints(endpoints =>endpoints.MapControllers());
        }
    }

Controller

     这些都是默认创建的Controller接口,程序启动后,调用接口则可以看到界面上的label控件发生改变,有兴趣的可以下载下来自己尝试尝试。

[ApiController]
    [Route("[controller]")]

    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;
        public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration,Form1 form1)
        {
            _logger = logger;
            Form1 = form1;
        }

        public Form1 Form1 { get; }

        [HttpGet("GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
#if WINDOWS
            Form1.label.Text=Guid.NewGuid().ToString();
#endif
            return WeatherForecasts();
        }
        private IEnumerable<WeatherForecast> WeatherForecasts([CallerMemberName] string memberName = "",
        [CallerFilePath] string sourceFilePath = "",
        [CallerLineNumber] int sourceLineNumber = 0)
        {

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

结尾

     感谢群里小伙伴提供的思路,让我能水一篇博客,哈哈,如果有对单片机感兴趣的也可以联系我,我会把我所知道的,倾囊相授。联系我可以在QQ群看有没有叫四川观察的,就是我,或者加QQ群6406277,也可以找到我。

    代码地址:http://121.43.235.192:8082/s/dzib6ywpCncDfLG