• [问题求助] linux发布之后找不到数据库
    开发是用windows开发的,发版是Linux环境,Windows环境发版没有问题【主库】Next recovery time: 2024/1/15 17:50:50 (ERROR [01000] [unixODBC][Driver Manager]Can't open lib '/usr/lib64/psqlodbcw.so' : file not found)【主库】Next recovery time: 2024/1/15 17:41:38 (ERROR [01000] [unixODBC][Driver Manager]Can't open lib 'PostgreSQL Unicode' : file not found)
  • [问题求助] Can't open lib 'PostgreSQL Unicode' : file not found
    .net windows 开发好了,都是通的,linux环境发布之后为什么连不上数据库了 ? 装上了linux的驱动 但还是一直找不到文件  是开发的链接字符串也要改嘛
  • [活动打卡] Day1ASP.NET Core 基础
    .net core 开源跨平台,集成当前各种流行的技术框架;.net 6为长期支持版本,.net core 2/3即将关闭支持;中间模式是非常优秀的设计和特色,next(),可无限的加中间处理过程;模块化是非常好的设计;适合各类网页、iot、桌面、app的运用开发,适合云原生的开发;云原生开发是一个庞大的开发体系,并不是单单的某个开发语言或环境;devops是个大趋势;
  • 云享读书会《深入浅出ASP.NET Core》
    https://developer.huaweicloud.com/signup/2e4da6016dac4fb18d20e05fa0fd72bc 有邀请活动
  • [获奖公告] 【奖品已于7月22日邮寄】【云享读书会第11期】《深入浅出ASP.NET Core》专家坐堂Q&A,还有礼品送不停哦~
    始活动前,请先报名本期读书会https://developer.huaweicloud.com/activity/reading_11.html--------------------------------------------------------------开发者,你好哟~华为云 · 云享读书会 第11期 它来了 !本期领读书籍为《深入浅出ASP.NET Core》由领读书籍原作者、华为云MVP、微软MVP、华为云云享专家、Microsoft Tech Summit 讲师、52ABP框架作者——梁桐铭老师,带你精读这本深入浅出ASP.NET Core!经过老师的视频领读,如果你有相关知识收获,欢迎在此帖留下你的读书笔记~获奖信息公示(公示期截止7月5日)优秀问答奖云之山zekelove幸运奖Allen2000张辉禄仁恝孙小北仲劲抽奖过程详见附件。恭喜以上开发者获得活动奖励,请点击下方链接填写获奖信息,请于7月20日前完成填写,过期视为弃奖哦~如有任何疑问可以和小助手联系~https://devcloud.huaweicloud.com/expert/open-assessment/qtn?id=3d3d196636fc4df9874cd247e36418bd&utm_source=ASPNetCore活动时间2021.06.20 - 2021.06.2702. 回复内容要求1. 可以提出您在课程学习中产生的任何疑问或者问题,也可以是您产生的深刻思考,我们统统欢迎;2. 禁止抄袭或复制读书笔记帖的任何内容;3. 您也可以参考以下互动话题,与领读专家和其他同学互动交流;4. 回帖时请务必留下你的微信昵称和华为云账号。03. 互动话题请说说您在本次课程中的收获04. 注意事项1. 小助手会在活动结束后按续完成审核,并增加活动积分20活动积分/人,优质回复额外增加50或100活动积分/人;2. 本次活动通过参与专家坐堂Q&A,可获得的积分上限为120分;3. 请务必按照上述要求提交内容,以免影响积分增加;4. 若积分值相同则以完成学习任务的时间先后排序,其中任务完成时间的判定优先级为:读书笔记>自测题>专家Q&A>其他;5. 其他积分获取方式请查看活动社群公告;6. 其他未说明事项请参照 云享读书会《深入浅出ASP.NET Core》05. 参与奖励针对活动时间内提交的有效读书笔记,领读专家将根据回复质量综合评选2位优秀奖获奖者,并奖励提交人 公牛插排魔方 一个同时抽取5位幸运奖获奖者,奖励 手机支架 一个(与优秀奖不兼得)06. 关于云享读书会每期云享读书会活动,会选取一本技术相关的畅销书籍,由原作者/行业专家提炼书籍精华,在读书会的专属微信社群中,每日输出精华知识的领读视频,帮助大家快速积累专业知识。活动期间会设置每日自测题、结业实践任务、提交读书笔记三种积分获取任务,并根据活动结束后的积分排行发放活动奖励。07. 加入学习社群然后添加小助手微信,备注“NET Core”加入学习社群。
  • [获奖公告] 【奖品已于7月22日邮寄】【云享读书会第11期】《深入浅出ASP.NET Core》读书笔记征集,更有礼品相送~
    开始活动前,请先报名本期读书会https://developer.huaweicloud.com/activity/reading_11.html--------------------------------------------------------------开发者,你好哟~华为云 · 云享读书会 第11期 它来了 !本期领读书籍为《深入浅出ASP.NET Core》由领读书籍原作者、华为云MVP、微软MVP、华为云云享专家、Microsoft Tech Summit 讲师、52ABP框架作者——梁桐铭老师,带你精读这本深入浅出ASP.NET Core!经过老师的视频领读,如果你有相关知识收获,欢迎在此帖留下你的读书笔记~获奖信息公示(公示期截止7月5日)最佳读书笔记奖励张辉花溪孙小北积分排名1~5名昵称Day1Day2Day3Day4Day5测试题1测试题2测试题3测试题4测试题5互动答疑总成绩孙小北 100100100100100100100100100100601060RabbitCloud100100100100100100100100100100601060allen2000100100100100100100100100100100601060zekelove100100100100100100100100100100601060夏暖100100100100100100100100100100601060积分排名6~15名张辉100100100100100100100100100100201020禄仁恝100100100100100100100100100100201020iolink1002100100100100100100100100100100201020仲劲100100100100100100100100100100201020AAAI100100100100100100100100100100201020HB168810010010010010010010010010075401015云水不言10010010010010010010010010010001000花溪10010010010010010010010010010001000Ethins10010010010010010010010010010001000yjh879238 10010010010010010010010010010001000恭喜以上开发者获得活动奖励,请点击下方链接填写获奖信息,请于7月20日前完成填写,过期视为弃奖哦~如有任何疑问可以和小助手联系~https://devcloud.huaweicloud.com/expert/open-assessment/qtn?id=3d3d196636fc4df9874cd247e36418bd&utm_source=ASPNetCore征集时间2021.06.15 - 2021.06.27读书笔记要求1. 每篇读书笔记字数要求≥300字;2. 内容要求与每日领读视频、领读书籍或是其他.NET Core技术领域相关;3. 内容原创不可抄袭;4. 回帖时请务必留下你的微信昵称和华为云账号。03. 注意事项1. 读书笔记提交后,小助手会在3个工作日内按续完成审核,并增加活动积分100活动积分/篇;2. 本次活动通过提交读书笔记,可获得的积分上限为500分;3. 请务必按照上述要求提交内容,以免影响积分增加;4. 若积分值相同则以完成学习任务的时间先后排序,其中任务完成时间的判定优先级为:读书笔记>自测题>专家Q&A>其他;5. 其他积分获取方式请查看活动社群公告;6. 其他未说明事项请参照 云享读书会《深入浅出ASP.NET Core》04. 最佳读书笔记奖励针对活动时间内提交的有效读书笔记,领读专家将根据内容质量和完成篇数综合评选3位最佳读书笔记获奖者,并奖励提交人荣耀猎人路由器1个05. 活动排行奖励最终积分排名1~5名     最终积分排名6~15名06. 关于云享读书会每期云享读书会活动,会选取一本技术相关的畅销书籍,由原作者/行业专家提炼书籍精华,在读书会的专属微信社群中,每日输出精华知识的领读视频,帮助大家快速积累专业知识。活动期间会设置每日自测题、结业实践任务、提交读书笔记三种积分获取任务,并根据活动结束后的积分排行发放活动奖励。07. 加入学习社群然后添加小助手微信,备注“NET Core”加入学习社群。
  • asp.net发布网站的步骤
    1、用VS2013打开解决方案。  2、选中解决方案,点击鼠标“右键”—>从弹出对话框中,选择“清理解决方案”。3、待第2步“清理解决方案”结束后,选中“解决方案”—>点击鼠标“右键”—>在弹出对话框中,选择“重新生成解决方案”。4、待第3步“重新生成解决方案”结束后,选择web运用程序,如下图中“testDemo”—>点击鼠标“右键”—>在弹出对话框中,选择“发布”。5、设置“配置文件”节点,点击“下一步”。6、设置“连接”节点,点击“下一步”。7、设置“设置”节点,点击“下一步”。8、设置“预览”节点,点击“发布”。9、发布后的文件如下图,此时文件发布成功,发布成功后,点开文件夹,所有页面的.cs文件都放进bin里面了。二、IIS安装1、打开“控制面板”—>选择“程序”。2、在弹出对话框中选择“启用或关闭Windows功能”。3、在弹出对话框中,选择“Internet Information Services”(如果初学者,建议全部选择,对于老手,按需选择),点击“确定”。4、点击确定后,系统正在运用所做的更改。5、运用程序更改结束后,选择“立即重新启动”。系统重新启动后,则IIS配置结束。6、重启电脑后,测试IIS配置是否成功。在浏览器栏,输入“http://localhost”,若出现如下界面,则表示IIS安装成功。三、IIS发布网站1、在“我是Cortana,小娜,有问题尽量问我”输入框输入“Internet Information Services”.2、打开IIS主界面。3、选择“网站”—>点击鼠标“右键”,在弹出对话框中,选择“添加网站”。4、在弹出对话框中,设置相关参数。5、此时,IIS主界面,“网站”多了一个站点“www.testWebSite”,即是刚才给站点取得名字。 6、配置运用程序池7、配置默认文档 8、默认文档添加成功后,如下图所示:9、为了防止权限不足,将刚才发布的文件添加成员“everyone”,并赋予权限。右键—>属性—>安全—>编辑—>添加     —>输入“everyone”—>为用户everyone赋权限—>确定。10、注册IIS。在所用程序中找到大写V,选择“Visual Studio 2013”—>选择“Visual Studio Tools”—>以管理员身份选择“VS2013 开发人员命令提示”,进入CMD。输入"aspnet_regiis -i"。11、至此,整个发布结束。12、测试。在浏览器地址栏输入:”http://localhost:8090/sessionDemo.aspx“,访问。
  • [技术干货] Jexus 网站服务器和 ASP.NET 跨平台开发
    Mono 和 Jexus 网站服务器Mono 这个开源项目其实一直伴随着 .NET Framework 成长。Miguel de Icaza 先生早年一直领导者 Gnome 这个开源桌面系统的开发。在2000年微软公布了 C# 语言和 .NET Framework 之后,他非常感兴趣并且希望能把这些新技术带到 Linux 平台,于是一手建立了 Mono 这个项目和社区。现在 Mono 的稳定版本是 6.10,全面兼容.NET 5,是.NET 5统一框架下的2大运行时之一,相对于.NET Framework停留在4.8 版本,Mono一直在进化,在移动开发Xamain、前端Blazor具有一席之地,同时在服务器段也是.NET Core 有益补充。和 .NET Core  另起炉灶相比,Mono 处处都保持着和 .NET Framework 的兼容性。在微软2014年11月完全基于 MIT 协议开放 .NET Framework 参考代码后,Mono 立即开始集成微软的代码 ,非常明显的改善了兼容性。不过 Mono 保持了自己独立开发的 CLR 实现和 C# 编译器,有自己的 AOT 运行环境和 C# Shell。在应用程序框架方面,Mono 提供 WinForms 和 WebForms 支持,也包含了微软早已开源的 MVC 5、Web API 2 和 SignalR 2。在 Mono 这个稳固的基础之上,中国四川的一位微软 C# MVP 刘冰历时多年设计了一款免费的网站服务器,取名 Jexus,最新稳定版本是6.2。作为一款跨平台软件,它支持各种主流 Linux 发布版本和 FreeBSD,特别是国内应用创新领域对于华为的鲲鹏(ARM )和龙芯(MIPS/LoongArch)。从架构等技术特点来看,Jexus 也可以媲美 IIS 等商用服务器。比如它提供了多站点支持,拥有应用程序池来调度管理工作进程,具有良好的稳定性和容错能力。又比如它支持 HTTPS 和 WebSockets,支持 FastCGI 协议和 OWIN 标准。它不仅可以作为一款应用服务器,来托管各种 ASP.NET 4 应用(WebForms、MVC、Web API、SignalR),同样也可以作为一般服务器使用,包含 URL 重写、反向代理、压缩传输等基础功能和 SQL 注入预防等多项内置安全防护。Jexus for linux 有如下特点:支持多种操作系统:Jexus最初的设计目标是“跨平台的ASP.NET WEB服务器”,由于在Windows系统上,IIS已经是ASP.NET的优秀平台,所以,当前的Jexus以支持Linux和FreeBSD等非Windows系统为主要设计目标。正因为这个原因,就Linux/FreeBSD等平台的ASP.NET建设而言,Jexus具有特别重大的意义。高性能:“高性能”是Jexus的重要的设计目标。虽然Jexus基于Mono环境运行,但Jexus并非全部由Mono的.NET组件构成,对于涉及性能的关键代码,Jexus非常巧妙地大量采用了Linux/Unix本身的优秀特性,从代码层保证了Jexus的性能优势。同时,Jexus的框架特征也为高性能提供了基础保证。Jexus不象XSP那样,纯HTML也需要经过ASP.NET处理,更不象Apache和Nginx等服务器,需要通过插件的形式间接地对ASP.NET进行支持,Jexus把HMTL静态文件处理模块、ASP.NET处理模块、静态文件高速缓存机制、epoll/poll数据传输机制等进行了高度集成,从架构本身入手,最大限度地提高WEB服务器的处理能力和传输速度。安全性:Jexus内核含有安全监控机制,绝大多数恶意访问在进入网站前就会被Jexus直接禁止,这是Jexus有别于其它WEB服务器的又一大特色,所以,Jexus特别适合那些对安全要求较高的企业网站或政府网站使用。稳定性:从运行机制而言,Jexus系统中,有专门检测工作进程执行状态的管理单元,任何一个进程退出或者任何一个ASP.NET网站应用程序域退出,被会被管理单元发现并得到重启,从而保证了Jexus能够7*24小时不间断工作;从程序本身而言,Jexus程序代码力求简洁,BUG很少,同时,Jexus的每个版本在正式发布之前,都要经过严格的压力测试,影响稳定性的因素,几乎在正式发布之前即已被全部排除。功能强大:Jexus支持URL重写,支持多目标服务器的反向代理,支持PHP,支持GZIP压缩传输,并且,可以利用不同端口、不同虚拟路径、不同域名设置任意数量的网站,这些功能要素,表明了Jexus是一款功能完整而强劲的WEB服务器。安装、配置、操作极为简单,服务社区化,各种问题能得到快速的处理,有良好的后续服务支撑能力。总体上来说,jexus除其它通用服务器应用的静态处理与反向代理功能外,另外三个特色比较突出:一,真正纯国产;二,入侵检测;三,支持asp.net/core。鲲鹏(ARM)上部署 Jexus 有两种安装方式:1是使用官方自动安装脚本:curl https://jexus.org/release/arm64/install.sh|sudo sh安装完成的目录地址为/usr/jexus 2是使用手动安装,可以自定义目录,我们这里也安装到/usr/lexus/目录下方便理解      wget https://linuxdot.net/down/jexus-6.2.x-arm64.tar.gz      tar zxvf jexus-6.2.x-x64.tar.gz Jexus的配置文件cd siteconf/                    #进入配置文件目录vim web                   #新建一个配置文件名为web,并进行编辑####################### Web Site: web ########################################                                                                                port=80                        # 监听端口:使用域名的话为80root=/ /var/www/default        # 运行目录 .NetCore web项目需要把项目目录指向到wwwroot目录,不支持虚拟目录hosts=web.test.com            # 服务器绑定域名,在hosts做一个本地域名也可以,也可以是IP地址,这里就不做演示了# User=www-data# AspNet.Workers=2  # Set the number of asp.net worker processes. Defauit is 1.# addr=0.0.0.0# CheckQuery=false# NoLog=true                                                                                                AppHost={                        # 新建AppHost配置  cmd=/var/wwww/deault/myWeb;     # 进行dotnet 项目名.dll运行操作  root=/var/wwww/deault;              # 项目的工作目录  # port=5001                     # 可选项。表示这个应用程序的侦听端口,多个端口用英文逗号分隔  #OutLog=/log/out.txt;                 # OutLog:可选项。表示将这个应用程序的控制台输出重定向到指定的文件(需填写完整路径);  #ErrLog=/log/out.txt;                         # ErrLog:可选项。表示将这个应用程序的异常输出重定向到指定的文件(需填写完整路径),如果不原意输出日志,可以不用OutLog项。这时, jexus会自动关掉控制台输出  }确保配置和项目文件无误后,进入目录运行jexuscd /usr/jexussudo ./jws start ... OK.使用浏览器测试一下:设置开机启动新建 jexus.servicecd /lib/systemd/systemvi jexus.service添加如下配置[Unit]Description=jexusAfter=network.target[Service]Type=forkingExecStart=/usr/jexus/jws startExecReload=/usr/jexus/jws restartExecStop=/usr/jexus/jws stopPrivateTmp=true[Install]WantedBy=multi-user.targetjexus加入服务: systemctl enable jexus.service启动jexus服务: systemctl start jexus.service查看jexus服务状态: systemctl status jexus.service
  • [技术干货] ASP.NET Core服务器综述
    ASP.NET Core应用通过一个进程内的HTTP服务器实例实现运行,这个服务器实例侦听HTTP请求并将请求作为组成HttpContext的一组请求功能集暴露给我们的应用程序。ASP.NET Core搭载两个服务器实现:Kestrel是一个基于libuv的跨平台HTTP服务器,libuv是一个跨平台的异步I/O库WebListener是一个基于HTTP.SYS内核驱动的“Windows专用”HTTP服务器KestrelKestrel是包含在ASP.NET Core新项目模板中默认的web服务器。如果你的应用只接收来自内部网络的请求,你可以只使用Kestrel本身。如果你将你的应用部署在公共网络上,我们建议你使用IIS,Nginx或者Apache作为反向代理服务器。一个反向代理服务器接收来自网络的HTTP请求并且在经过一些初步处理后将请求传递到Kestrel服务器。过程如下图所示。对edge deployments(从公共网络上接触到流量的部署方式)使用反向代理最重要的一个原因就是安全性。因为Kestrel相对较新,对抵御安全攻击至今还没有一个完整的功能补充。安全性处理包括但不限于适当的超时,大小的限制,以及并发连接限制等问题。有关何时使用Kestrel与反向代理的更多信息,请参见Kestrel。IIS with Kestrel当你使用IIS或者IIS Express作为对ASP.NET Core的反向代理时,ASP.NET Core应用将运行在由该IIS工作进程分离出的一个进程中。在该IIS进程中,存在着一个特殊的IIS模块,它被用来协调反向代理的关系。它就是ASP.NET Core模块。ASP.NET Core模块的主要功能包括启动ASP.NET Core应用,当应用崩溃时处理重启,向应用传送HTTP流量。更多的信息,请参考ASP.NET Core Module。Nginx with Kestrel有关如何在Linux使用Nginx作为对Kestrel的反向代理服务器的更多信息,请参考Publish to a Linux Production Environment。Apache with Kestrel有关如何在Linux使用Apache作为对Kestrel的反向代理服务器的更多信息,请参考Using Apache Web Server as a reverse proxy。Jexus with Kestrel有关如何在Linux使用Jexus作为对Kestrel的转发服务器的更多信息,请参考 Jexus 5.8.2 正式发布为Asp.Net Core进入生产环境提供平台支持WebListener如果你在Windows上运行你的ASP.NET Core应用,你可以会遇到以下场景——你既想要在公共网络上部署你的应用,又不能使用IIS,这时,WebListener会是一个可供替代的选择。当你只想要在内网中部署你的应用时,WebListener可以被用来代替Kestrel,特别是当你需要Weblistener服务器支持功能中的某项而Kestrel恰好不支持的时候。对于内部网络场景,为了能达到最好的性能表现,我们通常推荐Kestrel服务器,但是在另一些场景中,你可以想要使用某项仅WebListener支持的功能。关于WebListener功能的更多信息,请参考WebListener。ASP.NET Core 服务器基础组件说明IApplicationBuilder在Startup类中的Configure方法暴露了IFeatureCollection类的ServerFeatures属性。Kestrel和WebListener服务器都只提供了一个单一的功能,IServerAddressesFeature,但是不同的服务器实现可能会显示额外的功能。IServerAddressesFeature可以用来找出哪些服务器实例端口在运行时被绑定。ServerFeatures 的注释为“Gets the set of HTTP features the application's server providers”。自定义服务器你可以创建自定义服务器实现以用来替代Kestrel或者WebListener。Open Web Interface for .NET(OWIN) guide 说明了怎么去实现一个Nowin-based IServer。你可以自由地实现你的应用所需的功能接口,但至少必须支持IHttpRequestFeature和IHttpResponseFeature接口。
  • [技术干货] 将传统 ASP.NET 应用迁移到 .NET Core
    现在越来越多的人在谈论. NET Core。诚然,.NET Core 是未来, 但是.NET Framework 仍在支持, 因为大量的应用程序无法在短时间内迁移。.NET Core 和 .NET Framework 就像电动汽车和汽油动力汽车。汽油车是成熟的,你可以毫无任何问题驾驶它,但电动车有它们的优势,并正在取代汽油车。所以,不要误会,你应该从今天开始迁移到. NET Core。我已经迁移了几个运行在完整.NET Framework和IIS上的传统ASP.NET/MVC项目到ASP.NET Core 2.x,可以运行在IIS或非IIS环境下。这篇文章针对的是新接触.NET Core,但有.NET Framework经验的开发人员,帮助他们将现有的应用更平滑的过渡到.NET Core上。1、迁移或重写有时候,我更喜欢用“重写“而不是”迁移“这个词,因为在有些情况下,.NET Core和.NET Framework是完全不同的两个东西。根据我的经验,大部分前端代码可以只做少量修改就直接移植到.NET Core,因为它们的本质毕竟是服务器技术无关的,天生跨平台的技术。至于后端代码,迁移成本取决于它们对Windows及IIS的耦合程度。我理解,有些应用会充分利用Windows 及 IIS 的特性,这样开发者就可以避免自己费力去实现一些功能。这些包括计划任务、注册表、活动目录或Windows服务等。这些并不能够直接迁移,因为.NET Core是跨平台的。对于这些部分,你可能需要考虑从重新设计业务逻辑,想一种可以实现相同功能,但不依赖于Windows 或IIS 组件的方法。对于无法迁移的历史遗留代码,你可能需要考虑重新设计整个应用的架构,将这些功能作为REST API暴露出来,可以使用.NET Framework上的ASP.NET Web API来实现。这样的话,你的ASP.NET Core 应用得以继续使用这些API并继续完成业务功能。即使你的应用使用了WCF服务,甚至更老的 ASMX 服务,也是可以搞的。因为.NET Core目前有WCF客户端可以调用WCF。2、NuGet 包管理请确保你需要使用的NuGet包支持 .NET Core 或 .NET Standard。如果不支持,那么你需要研究有没有可以替换的NuGet包,或者你是否能够自己写代码去实现相同的功能。.NET Standard 意味着这个包可以同时使用在.NET Framework 4.6.1+ 以及.NET Core,这是取代老的 Portable Class Library (PCL)的技术。所以,如果你看到一个包的依赖项里有.NET Standard,这意味着你能够将它安装到你的.NET Core工程中。有部分包,比如NLog有专门的.NET Core版本,比如 NLog.Web.AspNetCore,你应该选择使用这样的版本。你依然可以在.NET Core工程里引用一个.NET Framework的包,但是这会让你的应用只能跑在Windows上,不推荐这么做。我列出了一些热门使用的NuGet 包,它们都已经支持.NET Core:NLog.Web.AspNetCoreNewtonsoft.JsonHtmlAgilityPackRestSharpNUnitDapperAutoMapperMoq对于客户端包,比如 jQuery,请不要使用NuGet 将它们安装到.NET Core工程中,参见本文的 “客户端包管理” 章节。如果你使用 Visual Studio Code 做 .NET Core 开发,请注意,安装NuGet包的命令不是 Install-Package,那是给Visual Studio的 PowerShell host用的,在VSCode里,你需要使用dotnet CLI工具,比如:dotnet add package Newtonsoft.Json参见 https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package3、客户端包管理ASP.NET Core 曾经使用 Bower 去管理客户端包。但在ASP.NET Core 2.1 里,Bower 已经被移除了,因为作者不干了。因此,微软默认使用自家的包管理器 “Library Manager” 也叫 “libman” 去管理前端包。它能够在 Visual Studio 和 Visual Studio Code 中使用,甚至也能用 CLI 在命令行下使用。libman.json 可以直接编辑,也能在UI中更改,都有智能感知支持。我的建议是,如果你的应用不是重客户端的话,使用 libman 去管理前端包,因为其他技术比如NPM 太重量级了。你会希望在你的编译服务器上安装和配置NodeJS以及其他一切东西,仅仅为了拉取一个jQuery 库。更多详情可参见官方文档 https://docs.microsoft.com/en-us/aspnet/core/client-side/libman/?view=aspnetcore-2.14、Html / JavaScript / CSS你可以直接将这些文件复制到.NET Core工程里。但是请确保你已经把文件路径修改正确,比如CSS里的图片文件路径。因为传统ASP.NET / MVC 模板默认使用 “/Content/” 目录,而.NET Core模板使用“/css/”, “/js/”, “/lib/” 等目录,这并不是强制的,只是约定俗成的规范。如果你希望捆绑并压缩CSS 和JS 文件,有许多工具可以办到。我个人喜欢用VS的一款插件,叫做 “Bundler & Minifier” ,你可以从这里获取https://github.com/madskristensen/BundlerMinifier.这款插件可以在开发时生成捆绑及压缩的文件,但非编译或运行时。5、App_Data 文件夹在传统ASP.NET/MVC 应用中,你可以将数据文件保存到一个名为“App_Data”的特殊文件夹中,但这个东西在.NET Core里不复存在了。为了实现类似的功能,你需要自己创建一个名为“App_Data” 的文件夹,但位于“wwwroot”目录之外。然后像这样使用public void Configure(IApplicationBuilder app, IHostingEnvironment env){    // set    string baseDir = env.ContentRootPath;    AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(baseDir, "App_Data"));     // use    var feedDirectoryPath = $"{AppDomain.CurrentDomain.GetData("DataDirectory")}\\feed";}6、自定义 Http Headers在传统ASP.NET里,你可以在Web.Config 里像这样为每个响应都配置自定义的HTTP Header:<httpProtocol>  <customHeaders>    <add name="X-Content-Type-Options" value="nosniff" />  </customHeaders></httpProtocol>而在.NET Core里,如果你希望脱离Windows去部署你的应用,不可以使用Web.config文件。因此,你需要一个三方的 NuGet 包来完成这个功能:NetEscapades.AspNetCore.SecurityHeadersapp.UseSecurityHeaders(new HeaderPolicyCollection()    .AddCustomHeader("X-UA-Compatible", "IE=edge")    .AddCustomHeader("X-Developed-By", "Edi Wang"));详情参考https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders7、获取客户端IP地址以及 HttpContext在传统ASP.NET 里,我们能够通过 Request.UserHostAddress 来获取客户端IP地址。但这个属性在 ASP.NET Core 2.x 里是不存在的。我们需要通过另一种方式获取HTTP 请求信息。1. 在你的 MVC 控制器里定义一个私有变量private IHttpContextAccessor _accessor;2.  使用构造函数注入初始化它public SomeController(IHttpContextAccessor accessor){    _accessor = accessor;}3. 获取客户端IP地址_accessor.HttpContext.Connection.RemoteIpAddress.ToString()就是如此简单。如果你的 ASP.NET Core 工程是用MVC默认模板创建的,针对HttpContextAcccessor 依赖注入注册应该在Startup.cs 中完成:services.AddHttpContextAccessor();services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();RemoteIpAddress 的类型是 IPAddress 并不是string。它包含 IPv4, IPv6 以及其他信息。这和传统ASP.NET不太一样,对我们更加有用一些。如果你希望在Razor 视图(cshtml) 里使用,只需要用 @inject 指令注入到view中:@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor使用方法:Client IP: @HttpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString()8、JsonResult默认情况下,ASP.NET Core 会使用 camelCase 序列化 JsonResult ,而传统 ASP.NET MVC 使用的是PascalCase,这会导致依赖Json结果的 JavaScript 代码爆掉。例如以下代码:public IActionResult JsonTest(){    return Json(new { Foo = 1, Goo = true, Koo = "Test" });}它会返回camelCase 的Json给客户端:如果你有大量JavaScript 代码并不能及时改为使用camelCase,你仍然可以配置 ASP.NET Core 向客户端输出 PascalCase 的Jsonpublic void ConfigureServices(IServiceCollection services){    // Add framework services.    services.AddMvc()        .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());}现在,之前的代码会返回PascalCase 的结果:9、HttpModules 和 HttpHandlers这两者在ASP.NET Core中被替换为了 Middleware。但在迁移之前,你可以考虑使用别的方法,在一个普通ASP.NET Core Controller 中实现这些功能。例如,我的老博客系统里有个名为“opml.axd” 的HttpHandler 作用是向客户端输出一个XML文档,这其实完全可以用 Controller 来实现:public async Task<IActionResult> Index(){    var opmlDataFile = $"{AppDomain.CurrentDomain.GetData(Constants.DataDirectory)}\\opml.xml";    if (!System.IO.File.Exists(opmlDataFile))    {        Logger.LogInformation($"OPML file not found, writing new file on {opmlDataFile}");         await WriteOpmlFileAsync(HttpContext);        if (!System.IO.File.Exists(opmlDataFile))        {            Logger.LogInformation($"OPML file still not found, something just went very very wrong...");            return NotFound();        }    }     string opmlContent = await Utils.ReadTextAsync(opmlDataFile, Encoding.UTF8);    if (opmlContent.Length > 0)    {        return Content(opmlContent, "text/xml");    }     return NotFound();}我也曾经使用HttpHandler 完成Open Search,RSS/Atom等功能,它们也能够被 重写为Controller。对于其他一些不能够被重写为MVC Controller的组件,例如处理特殊拓展名的请求。请参见:https://docs.microsoft.com/en-us/aspnet/core/migration/http-modules?view=aspnetcore-2.110、IIS URL Rewrite你依然可以使用和旧应用里完全一样的配置文件,不管你的 .NET Core 应用是否部署在IIS上。例如,在应用根目录底下创建一个名为"UrlRewrite.xml"的文件,内容如下:<rewrite>  <rules>    <rule name="Redirect Misc Homepage URLs to canonical homepage URL" stopProcessing="false">      <match url="(index|default).(aspx?|htm|s?html|php|pl|jsp|cfm)"/>      <conditions logicalGrouping="MatchAll" trackAllCaptures="false">        <add input="{REQUEST_METHOD}" pattern="GET"/>      </conditions>      <action type="Redirect" url="/"/>    </rule>  </rules></rewrite>注意:你必须把这个文件设置为always copy到输出目录,不然无效!<ItemGroup>  <None Update="UrlRewrite.xml">    <CopyToOutputDirectory>Always</CopyToOutputDirectory>  </None></ItemGroup>打开 Startup.cs,在Configure 方法中添加如下代码:public void Configure(IApplicationBuilder app, IHostingEnvironment env){    ...    using (var urlRewriteStreamReader = File.OpenText("UrlRewrite.xml"))    {        var options = new RewriteOptions().AddIISUrlRewrite(urlRewriteStreamReader);        app.UseRewriter(options);    }    ...}这在我之前的文章中提到过https://edi.wang/post/2018/9/18/prevent-image-hotlink-aspnet-core.更多选项和用法可以参考 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.111、Web.configWeb.config 文件并没有完全消亡。在 In .NET Core 里,一个 web.config 文件仍然用于在IIS环境下部署网站。在这种场景下,Web.config 里的配置仅作用于 IIS,和你的应用代码没有任何关系。可以参考 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index?view=aspnetcore-2.1#configuration-of-iis-with-webconfig一个典型的IIS下部署ASP.NET Core应用的web.config 文件如下:<?xml version="1.0" encoding="utf-8"?><configuration>  <location path="." inheritInChildApplications="false">    <system.webServer>      <handlers>        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />      </handlers>      <aspNetCore processPath="dotnet" arguments=".\Moonglade.Web.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />    </system.webServer>  </location></configuration>曾经的 AppSettings 节点可迁移到 appsettings.json,在这篇文章中有详解:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.112、Session 和 CookieASP.NET Core 默认没有开启Session支持,你必须手工添加Session 支持。services.AddDistributedMemoryCache();services.AddSession(options =>{    options.IdleTimeout = TimeSpan.FromMinutes(20);    options.Cookie.HttpOnly = true;});以及app.UseSession();设定和获取Session值:HttpContext.Session.SetString("CaptchaCode", result.CaptchaCode);HttpContext.Session.GetString("CaptchaCode");清除值:context.Session.Remove("CaptchaCode");详情参见:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-2.113、Html.Action我们曾经使用 Html.Action 去调用一个Action ,返回一个Partial View ,然后放在主要的View 中显示,比如layout页。这在Layout页面中的应用非常广泛,比如在一个博客系统中显示分类列表之类的小部件。@Html.Action("GetTreeList", "Category")在ASP.NET Core里,它被替换为了 ViewComponents,参见 https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components一个要注意的地方是Invoke方法只能是 async 签名的:async Task<IViewComponentResult> InvokeAsync()但如果你的代码并不是天生异步的,为了不让编译器警报,你可以加入这行代码:await Task.CompletedTask;14、检查运行环境是 Debug 或 Release在我的老系统里,我使用 HttpContext.Current.IsDebuggingEnabled 去检查当前运行环境是否为Debug,并在标题栏上显示 “(Debug)” 字样。@if (HttpContext.Current.IsDebuggingEnabled){    <text>(Debug)</text>}在 ASP.NET Core 里,我们可以使用新的razor tag helper 去完成这件事<environment include="Development">    (Debug)</environment>在下面的章节里,你会看到更多razor tag helper 的用法。15、新的Razor Tag HelpersTag helper 可以帮助你讲老的HTML helper 简化为更加面向HTML可读的代码,例如一个表单,我们曾经要这样写:转换为 Tag Helpers 的结果是这样的:我个人最喜欢的功能是给JS或CSS文件自动增加版本字符串:<script src="~/js/app/ediblog.app.min.js" asp-append-version="true"></script>它的结果是:<script src="/js/app/ediblog.app.min.js?v=lvNJVuWBoD_RVZwyBT15T_i3_ZuEIaV_w0t7zI_UYxY"></script>新的razor 语法能够兼容以前的 HTML helpers,也就是说,你依然能在ASP.NET Core中毫无问题的使用老的 HTML helpers。如果你的应用迁移时间紧迫,你可以尽管先使用老代码,随后再逐步转换到Tag Helpers。完整的介绍和语法列表,可参见https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.116、Anti-Forgery TokenAnti-forgery token 有一些改进。首先,你能够自定义cookie 以及字段的名字了。services.AddAntiforgery(options =>{    options.Cookie.Name = "X-CSRF-TOKEN-MOONGLADE";    options.FormFieldName = "CSRF-TOKEN-MOONGLADE-FORM";});第二,你再也不需要手工给每一个表单都增加这行代码了:@Html.AntiForgeryToken()如果你使用新的form tag helper,那么anti-forgery 字段会自动在输出到客户端时自动加上。但你依然需要在后台对应的Action上加上 [ValidateAntiForgeryToken] 属性。然而,有另一种自动给每一个POST请求都验证anti-forgery token 的办法。services.AddMvc(options =>options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));或者你可以单独给一个 Controller 加上这个属性。[Authorize][AutoValidateAntiforgeryToken]public class ManageController : Controller17、对非Controller 使用依赖注入ASP.NET Core 有自带的 DI 框架可以用在 Controller 上。我们可以修改一个Controller 的构造函数去注入它运行所依赖的服务。public class HomeController : Controller{    private readonly IDateTime _dateTime;     public HomeController(IDateTime dateTime)    {        _dateTime = dateTime;    }}但这不意味着自带的DI框架只能用在Controller 上。对于其他类,你可以使用完全一样的DI,例如,我自定义的类,也可以使用构造函数注入:public class CommentService : MoongladeService{    private readonly EmailService _emailService;     public CommentService(MoongladeDbContext context,        ILogger<CommentService> logger,        IOptions<AppSettings> settings,        EmailService emailService) : base(context, logger, settings)    {        _emailService = emailService;    }          // ....}方法是,只要你把自定义的类注册到Startup.cs中的 DI 容器里即可。services.AddTransient<CommentService>();更多ASP.NET Core 依赖注入的使用方法参见 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-2.118、API 行为不一致有些来自传统 ASP.NET 的代码可以无错误编译通过,但这不保证运行时能够成功。比如,这段来自ASP.NET (.NET Framework) 的代码在 ASP.NET Core 中会抛出异常:var buffer = new byte[context.Request.Body.Length];context.Request.Body.Read(buffer, 0, buffer.Length);var xml = Encoding.Default.GetString(buffer);它的结果是:System.NotSupportedException: Specified method is not supported.at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.get_Length()在.NET Core里,我们需要用一种不同的方式去实现:var xml = await new StreamReader(context.Request.Body, Encoding.Default).ReadToEndAsync();19、小心GDPR 带来的问题ASP.NET Core 2.1 默认添加了 GDPR 的支持,但也会给我们带来一些问题。关于GDPR可参见 https://docs.microsoft.com/en-us/aspnet/core/security/gdpr?view=aspnetcore-2.1主要问题是,在用户接受GDPR协议之前,Cookie 是不起作用的。你需要检查哪些Cookie是你应用运行所必须的,即时用户没有接受GDPR协议,并且把它们标记为IsEssential这是我博客系统中的一个例子:private void SetPostTrackingCookie(CookieNames cookieName, string id){    var options = new CookieOptions    {        Expires = DateTime.UtcNow.AddDays(1),        SameSite = SameSiteMode.Strict,        Secure = Request.IsHttps,         // Mark as essential to pass GDPR        // https://docs.microsoft.com/en-us/aspnet/core/security/gdpr?view=aspnetcore-2.1        IsEssential = true    };     Response.Cookies.Append(cookieName.ToString(), id, options);}另一个问题是,如果你要使用Session,那么用户必须接受GDPR 策略,否则 Session是不工作的。因为 Session 需要依赖 Cookie 在客户端保存 SessionID 。20、热更新 Views在传统 ASP.NET MVC 中,Views 文件夹默认不会编译到 DLL 文件中,所以我们能够不需要编译整个应用就能更新razor页面。这在不需要更新C#代码的情况下仅修改文字或一些layout修改的场景下非常实用。我有时候也利用这个特性直接向生产环境发布一些修改后的页面。然而,ASP.NET Core 2.1 默认情况下会将我们的 Views 编译到DLL 中以提高性能。因此,你无法在服务器上直接修改一个视图,因为文件夹中根本就不存在 Views,只有一个 *.Views.dll:如果你仍然希望在ASP.NET Core中热更新Views,需要手工修改csproj文件:<PropertyGroup>  <TargetFramework>netcoreapp2.1</TargetFramework>  <RazorCompileOnBuild>false</RazorCompileOnBuild>  <RazorCompileOnPublish>false</RazorCompileOnPublish></PropertyGroup>21、编译版本号自增长在传统 .NET 应用程序里,我们可以修改 “AssemblyInfo.cs” 在每次编译时自动增加版本号。这在编译服务器里十分常用。[assembly: AssemblyVersion("9.0.*")]结果是这样:9.0.6836.29475不幸的是,.NET Core 目前还没有一个自带的方法来完成这个操作。只有一个三方解决方案可能有用:https://github.com/BalassaMarton/MSBump总结ASP.NET Core 相对传统 ASP.NET 有了不少区别,目前也有一定的限制。本文仅涵盖了我自己所遇到的问题,也一定还有很多我没有遇到过的情况。本文转载自公众号文章:https://mp.weixin.qq.com/s/SxFAUV5_8xpJY6R8inLSvA
  • [技术干货] 【趁热打“帖”】Asp.net core实现北向应用服务对接OceanConnect
        华为IoT教程和帮助文档给出的Demo唯独缺少.net的样例,在上次刚刚实现了Asp.net core作为服务对接。使用的Api接口:login/subscriptions/deviceCommands主动调用的接口deviceDataChanged/commandChanged提供给回调的服务调用OceanConnect接口特点header信息app_key为header必须的除了login其他接口的header必须带token请求ContentType分为2种application/x-www-form-urlencoded和application/json 请求必须携带认证证书(证书见附件,密码IoM@1234)基于以上可以总结出通用请求方法/// <summary> /// IoT Post请求 /// </summary> /// <param name="url">完整url</param> /// <param name="content">HttpContent或其子类</param> /// <param name="token">有效token</param> /// <returns></returns> public async Task<string> Post2(string url, HttpContent content, string token) { var handler = new HttpClientHandler { CheckCertificateRevocationList = false, ClientCertificateOptions = ClientCertificateOption.Manual, SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 }; content.Headers.Add("app_key", AppId); if (content is FormUrlEncodedContent) content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); else if (content is StringContent) content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); handler.ClientCertificates.Add(new X509Certificate2(CertificateFilePath, CertificatePassword)); handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; }; using (var client = new HttpClient(handler)) { if (!string.IsNullOrEmpty(token)) { var authValue = new AuthenticationHeaderValue("Bearer", token); client.DefaultRequestHeaders.Authorization = authValue; } HttpResponseMessage response = await client.PostAsync(url, content); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } }登陆方法public LoginResult Login() { var url = "https://ip:port/iocm/app/sec/v1.1.0/login"; var dic = new Dictionary<string, string> { { "appId", AppId }, { "secret", Secret } }; var body = new FormUrlEncodedContent(dic); try { var result = helper.Post2(url, body, null).GetAwaiter().GetResult(); var login = JsonConvert.DeserializeObject<LoginResult>(result); Token = login.AccessToken; return login; } catch (Exception ex) { _log.LogError(ex, "Login 异常:"); return null; } }订阅deviceDataChanged消息public string Subscript() { CheckToken(); var url = "https://ip:port/iocm/app/sub/v1.2.0/subscriptions?ownerFlag=true"; var param = new Dictionary<string, string> { { "appId", AppId }, { "notifyType", "deviceDataChanged" }, { "callbackUrl", "http://ip:port/api/clock/DeviceDataChanged" }, { "channel", "http" } }; var body = JsonConvert.SerializeObject(param); try { var html = helper.Post2(url, new StringContent(body), Token).GetAwaiter().GetResult(); var result = JsonConvert.DeserializeObject<IoTSubscriptResult>(html); return html; } catch (Exception ex) { _log.LogError(ex, "Subscript 异常"); return ex.Message; } }一个通用的设备命令方法private bool SendDeviceCommands(IoTCmdReq param) { CheckToken(); var url = $"https://ip:port/iocm/app/cmd/v1.4.0/deviceCommands?appId={AppId}"; var body = JsonConvert.SerializeObject(param, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }); try { var html = helper.Post2(url, new StringContent(body), Token).GetAwaiter().GetResult(); var result = JsonConvert.DeserializeObject<IoTCmdResult>(html); var success = new List<IoTCmdStatus> { IoTCmdStatus.DELIVERED, IoTCmdStatus.PENDING, IoTCmdStatus.SENT, IoTCmdStatus.SUCCESSFUL }; return success.Contains(result.Status); } catch (Exception ex) { _log.LogError(ex, "SendDeviceCommands 异常"); return false; } }一个设备命令样例private bool SetCall(string content, string deviceId) { var param = new IoTCmdReq { DeviceId = deviceId, Command = new IoTCmd { ServiceId = "Call", Method = "Set_Call", Paras = new Dictionary<string, object> { { "content", content } } }, CallbackUrl = "http://ip:port/api/clock/CommandChanged", ExpireTime = 10, MaxRetransmit = 2 }; return SendDeviceCommands(param); }接收回调设备数据变化命令/// <summary> /// 订阅数据变化回调入口 /// </summary> [HttpPost] [Route("[action]")] public void DeviceDataChanged() { string inputbody; using (var reader = new System.IO.StreamReader(HttpContext.Request.Body, Encoding.UTF8)) { inputbody = reader.ReadToEnd(); } var reqdata = JsonConvert.DeserializeObject<IoTDataChangedReq>(inputbody); if (reqdata.Service.ServiceId == "Clock") { _service.Welcome(reqdata.Service.Data["card_no"].ToString(), reqdata.DeviceId); } else if (reqdata.Service.ServiceId == "Sensor") { } }