工作需要,我想在一個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(); } }
IMyApiHost用於啟動一個asp.net core的實例。其實以下整個過程就是將上面的IFormUI接口傳入asp.net core的注入系統中。
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(); } //........ }
好了,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(); } } }
好了,IFormUI在asp.net core的注入系統中准備好了,Controller可以使用IFormUI來控制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); } } }
好了,最后一步,在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); } }
以下是程序運行效果。web程序已可控制了winform程序
作者聲明:本文只發布在“博客網”,未經作者同意,請勿轉載!謝謝!余映畫 2022-2-20