工作需要,我想在一个windows程序中提供webAPI的来提供打印服务。于是想到将asp.net core做的webapi放在windows上。今天又冷又下雨,哪也不去了,就在家为公司的方案做一些技术调研吧。
asp.net core是可能跑在命令行下的。于是想能否直接转为一个windows程序呢?是可以的,项目的选项就有,只是不彻底。就是无法添加新的Form。于是点击项目文件,看其文本,修改为类似以下形式,就变成一个真正的winform项目。不过在2019会有错误,在这种项目下添加的Form,打开设计界面打开会报错。所以winform还在放在其他项目吧。
有博主将asp.net core项目以引用的方式添加到wpf的程序里,在wpf里直接调用。不过我使用winform项目引用添加asp.net core项目时,也会报上面所说的一样的错误。于是,我将asp.net core转为winform项目后,作为主项目使用。另建一个winform项目编译所有的Form,以引用的形式添加到主项目。
net5有注入,所以我就用net5开始了我的摸索。注入的知识可以看以下地址
https://www.cnblogs.com/artech/p/net-core-di-06.html
先定义两个交互的接口
namespace WebApi.Interface { /// <summary> /// 宿主创建 /// </summary> public interface IMyApiHost { Microsoft.Extensions.Hosting.IHost BuildHost(IFormUI formUI); } /// <summary> /// 主UI界面 /// </summary> public interface IFormUI { string SayHello(string name); string[] GetCommandArgs(); } }View Code
winform项目准备一个启动器给主项目使用
namespace WebApiTestOnWin.App { /// <summary> /// 界面启动器。 /// </summary> public class UIStarter { public IServiceProvider ApplicationService { get; private set; } public IServiceProvider ScopedService { get; private set; } public void StartConfig(IMyApiHost apiHost) { var services = new ServiceCollection(); services.AddSingleton<MainForm>(); services.AddSingleton(apiHost); ApplicationService = services.BuildServiceProvider(); ScopedService = ApplicationService.CreateScope().ServiceProvider; } public Form BuildMainForm() { var mainWindow = ScopedService.GetRequiredService<MainForm>(); return mainWindow; } } }
对于winform来说IMyApiHost是未知的。以下是MainForm的部分代码。原构造函数需要加上一个入参,以接收这个必要的IMyApiHost。
namespace WebApiTestOnWin.App { public partial class MainForm : Form,IFormUI { IMyApiHost myHost; //public Form1() //{ // InitializeComponent(); //} public MainForm(IMyApiHost api) { InitializeComponent(); this.myHost = api; } private void button1_Click(object sender, EventArgs e) { myHost.BuildHost(this).RunAsync();//启动asp.net core } public string SayHello(string name) { if (this.InvokeRequired) { var result = this.BeginInvoke(new SayHandler(this.SayHello), new object[] { name }); result.AsyncWaitHandle.WaitOne(-1); return (string)this.EndInvoke(result); } this.lblMsg.Text = name + " saying..."; return $"hi! {name},it's form."; } public string[] GetCommandArgs() { return Environment.GetCommandLineArgs(); } //........ }View Code
好了,winform项目准备好了。看看asp.net core如何使用这个UIStarter。
使用前,asp.net core需要准备IMyWebApiHost的实现。其实就是将asp.net core的启动包装起来,以备MainForm使用。
namespace WebApiSimpleSite { public class MyWebApiHostBuilder : MarshalByRefObject, IMyApiHost { IFormUI myFormUI; IHost host; public Microsoft.Extensions.Hosting.IHost BuildHost(IFormUI formUI) { myFormUI = formUI; string[] args = formUI.GetCommandArgs(); var builder = Host.CreateDefaultBuilder(args); var host = builder.ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureServices((svc)=>svc.AddSingleton(myFormUI) ); webBuilder.UseStartup<Startup>(); }); return host.Build(); } } }
好了,程序准备好了。在asp.net core(已手工转换为winform程序)中启动MainForm
namespace WebApiSimpleSite { public class Program { public static void Main(string[] args) { //CreateHostBuilder(args).Build().Run(); //原启动asp.net core的命令行代码 UIStarter starter = new UIStarter();//引用winform后,使用其UIStarter starter.StartConfig(new MyWebApiHostBuilder());//将asp.net core的启动器传入,以完成其配置 Form formMain = starter.BuildMainForm();//创建主程序 Application.Run(formMain); } }
IFormUI是准备给Controller使用的。目的就是利用webapi控制winform。以下是Hello方法测试了这个过程
namespace WebApiSimpleSite.Controllers { [Route("api/[controller]")] [ApiController] public class PrintController : ControllerBase { IFormUI myFormUI; public PrintController(IFormUI formUI) { myFormUI = formUI; } [HttpGet] public string Hello(string yourname) { return myFormUI.SayHello(yourname); } } }
以下是程序运行效果。web程序已可控制了winform程序