主頁 > .NET開發 > 基于ASP.NET core的MVC站點開發筆記 0x01

基于ASP.NET core的MVC站點開發筆記 0x01

2020-09-09 23:11:55 .NET開發

基于ASP.NET core的MVC站點開發筆記 0x01

我的環境

OS type:mac
Software:vscode
Dotnet core version:2.0/3.1

dotnet sdk下載地址:https://dotnet.microsoft.com/download/dotnet-core/2.0

準備

先到上面提供的下載地址,下載對應平臺的dotnet裝上,然后在命令列視窗輸入dotnet --version查看輸出是否安裝成功,

然后,安裝visual studio code,安裝之后還需要安裝C#拓展,要不然每次打開cs檔案都會報錯,

創建專案

新建一個空目錄,例如mvc-test

使用命令dotnet new查看可以新建的專案型別:

第一次嘗試,使用ASP.NET Core Empty就可以,代號是web,使用命令dotnet new web就可以新建一個空專案,專案的名稱就是當前目錄的名字mvc-test

專案結構與默認配置

目錄主要結構和檔案功能如下:

Program.cs是程式的主類,Main函式在這里定義,內容大致可以這么理解:

CreateDefaultBuilder函式會使用默認的方法載入配置,例如通過讀取launchSettings.json確定當前的發布環境:

webhost通過ASPNETCORE_ENVIRONMENT讀取發布環境,然后會讀取對應的組態檔,Development對應appsettings.Development.jsonProduction對應appsettings.json

appsettings檔案是整個web應用的組態檔,如果web應用需要使用某個全域變數,可以配置到這個檔案里面去,

webhost在運行前會通過Startup類,進行一些中間件的配置和注冊,以及進行客戶端的回應內容設定:

注:dotnet core 3版本里,取消了WebHost,使用Host以更通用的方式進行程式托管,

dotnet core 3 Program.cs

public static Void Main(string[] args)
{
    Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(builder =>
    {
        builder.UseStartup<Startup>();
    }).Build().Run();
}

獲取組態檔中的值

修改launingSettings.json中設定的發布環境對應的組態檔,例如appsetttings.Delelopment.json內容,添加一個Welcome欄位配置項,如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "Welcome": "Hello from appsettings.json!!"
}

修改Startup.cs檔案,添加IConfiguration config引數,.net core內部會將組態檔內容映射到這個變數:

/// <summary>
/// 注冊應用程式所需的服務
/// </summary>
public void ConfigureServices(IServiceCollection services)
{
}

/// <summary>
/// 注冊管道中間件
/// </summary>
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IConfiguration config)
{
    // 開發環境,使用開發者例外界面
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    var welcome = config["Welcome"];

    // Run一般放在管道末尾,運行完畢之后直接終止請求,所以在其后注冊的中間件,將不會被執行
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(welcome);
    });
}

在終端中使用命令dotnet run可以運行這個web應用:

瀏覽器訪問http://localhost:5000,可以看到已經成功獲取到Welcome配置項的值:

日志列印

通過ILogger實作控制臺日志的列印:

public void ConfigureServices(IServiceCollection services)
{
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    var welcome = config["Welcome"];

    logger.LogInformation(welcome);

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(welcome);
    });
}

ILogger使用的時候需要指定列印日志的類名Startup,最終列印效果如下:

服務注冊

上面的IConfiguration可以直接使用,是因為IConfiguration服務已經自動注冊過了,

對于自定義的服務,可以在ConfigureServices中注冊,例如自定義一個服務WelcomeService,專案目錄下新建兩個檔案IWelcomeService.csWelcomeService.cs,內容如下:

/* IWelcomeService.cs
 *
 * 該介面類定義了一個getMessage方法,
 */
namespace mvc_test
{
    public interface IWelcomeService
    {
        string getMessage();
    }
}
/* WelcomeService.cs
 *
 * 該類實作了getMessage方法,
 */
 namespace mvc_test
{
    public class WelcomeService : IWelcomeService
    {
        int c = 0;
        public string getMessage()
        {
            c++;
            return "Hello from IWelcomeService Interface!!!" + c.ToString();
        }
    }
}

然后在ConfigureServices中注冊服務:

public void ConfigureServices(IServiceCollection services)
{
        services.AddSingleton<IWelcomeService, WelcomeService>();
}

然后在Configure中使用的時候需要傳參:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger,
    IWelcomeService welcomeService)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    //var welcome = config["Welcome"];
    var welcome = welcomeService.getMessage();

    logger.LogInformation(welcome);

    // Run一般放在管道末尾,運行完畢之后直接終止請求,所以在其后注冊的中間件,將不會被執行
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(welcome);
    });
}

運行后結果:

這個例子中,注冊服務使用的函式是AddSingleton,服務的生命周期除了Singleton,還有其他兩個模式:ScopedTransient

這三個模式的區別:

  • Transient:瞬態模式,服務在每次請求時被創建,它最好被用于輕量級無狀態服務;
  • Scoped:作用域模式,服務在每次請求時被創建,整個請求程序中都貫穿使用這個創建的服務,比如Web頁面的一次請求;
  • Singleton:單例模式,服務在第一次請求時被創建,其后的每次請求都用這個已創建的服務;

參考資料:

  • NetCore2.0依賴注入(DI)之生命周期
  • Service lifetimes

初始學習使用AddSingleton就行了,

中間件和管道

中間件是一種用來處理請求和回應的組件,一個web應用可以有多個中間件,這些中間件共同組成一個管道,每次請求訊息進入管道后都會按中間件順序處理對應請求資料,然后回應結果原路回傳:

參考資料:

  • ASP.NET Core 中間件

內置中間件的使用:處理靜態檔案訪問請求

新建一個目錄wwwroot,目錄下新建index.html檔案:

<html>
    <head>
        <title>TEST</title>
    </head>
    <body>
        <h1>Hello from index.html!!!</h1>
    </body>
</html>

使用之前的代碼,dotnet run運行之后訪問http://localhost:5000/index.html,發現還是之前的結果,并沒有訪問到index.html

這時候需要使用中間件StaticFiles來處理靜態檔案的請求,修改Startup.cs的部分內容如下:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger,
    IWelcomeService welcomeService)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseStaticFiles();

    //var welcome = config["Welcome"];

    app.Run(async (context) =>
    {
        var welcome = welcomeService.getMessage();
        logger.LogInformation(welcome);
        await context.Response.WriteAsync(welcome);
    });
}

重新啟動后可正常訪問到index.html

前面講到請求進入管道之后是安裝中間件添加順序處理的請求,如果當前中間件不能處理,才會交給下一個中間件,所以可以嘗試一下將上面的代碼調整一下順序:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger,
    IWelcomeService welcomeService)
{
    if (env.IsDevelopment())
    {?
        app.UseDeveloperExceptionPage();
    }

    //var welcome = config["Welcome"];

    app.Run(async (context) =>
    {
        var welcome = welcomeService.getMessage();
        logger.LogInformation(welcome);
        await context.Response.WriteAsync(welcome);
    });

    app.UseStaticFiles();
}

可以看到StaticFiles放到了最后,這樣的話因為index.html請求會先到Run的地方,直接回傳了,所以不能進入到StaticFiles里,訪問得到的內容就是:

通過StaticFiles可以成功訪問到index.html,但是如果想要index.html成為默認網站主頁,需要使用中間件DefaultFiles,修改上面代碼為:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger,
    IWelcomeService welcomeService)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();

    //var welcome = config["Welcome"];

    app.Run(async (context) =>
    {
        var welcome = welcomeService.getMessage();
        logger.LogInformation(welcome);
        await context.Response.WriteAsync(welcome);
    });
}

DefaultFiles內部會自動將/修改為index.html然后交給其他中間件處理,所以需要放在StaticFiles的前面,

使用FileServer也可以實作同樣的效果:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    IConfiguration config, 
    ILogger<Startup> logger,
    IWelcomeService welcomeService)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseFileServer();

    //var welcome = config["Welcome"];

    app.Run(async (context) =>
    {
        var welcome = welcomeService.getMessage();
        logger.LogInformation(welcome);
        await context.Response.WriteAsync(welcome);
    });
}

中間件的一般注冊方式

除了使用內置的中間件之外,還可以用以下幾種方式注冊中間件:

  • Use
  • UseWhen
  • Map
  • MapWhen
  • Run

UseUseWhen注冊的中間件在執行完畢之后可以回到原來的管道上;
MapMapWhen可以在新的管道分支上注冊中間件,不能回到原來的管道上;
When的方法可以通過context做更多的中間件執行的條件;
Run用法和Use差不多,只不過不需要接收next引數,放在管道尾部;

例如實作回傳對應路徑內容:

/// <summary>
/// 注冊應用程式所需的服務
/// </summary>
public void ConfigureServices(IServiceCollection service)
{
    
}

/// <summary>
/// 注冊管道中間件
/// </summary>
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    // 開發環境,添加開發者例外頁面
    if(env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Use 方式
    app.Use(async (context, next) =>
    {
        if(context.Request.Path == new PathString("/use"))
        {
            await context.Response.WriteAsync($"Path: {context.Request.Path}");
        }
        await next();
    });

    // UseWhen 方式
    app.UseWhen(context => context.Request.Path == new PathString("/usewhen"),
    a => a.Use(async (context, next) =>
    {
        await context.Response.WriteAsync($"Path: {context.Request.Path}");
        await next();
    }));

    // Map 方式
    app.Map(new PathString("/map"),
    a => a.Use(async (context, next) =>
    {
        // context.request.path 獲取不到正確的路徑
        //await context.Response.WriteAsync($"Path: {context.Request.Path}");
        await context.Response.WriteAsync($"PathBase: {context.Request.PathBase}");
        foreach(var item in context.Request.Headers)
        {
            await context.Response.WriteAsync($"\n{item.Key}: {item.Value}");
        }
    }));

    // MapWhen 方式
    app.MapWhen(context => context.Request.Path == new PathString("/mapwhen"),
    a => a.Use(async (context, next) =>
    {
        await context.Response.WriteAsync($"Path: {context.Request.Path}");
        await next();
    }));

    // Run 放在最后,可有可無,主要為了驗證是否可以回到原來的管道上繼續執行
    app.Run(async (context)=>
    {
        await context.Response.WriteAsync("\nCongratulation, return to the original pipe.");
    });
}

可以看到只有/use/usewhen可以執行到Run

注:這里碰到一個問題,就是訪問/map路徑的時候獲取到的context.Request.Path為空,其他欄位獲取都挺正常,神奇,不過,可以使用context.Request.PathBase獲取到,

自己封裝中間件

對于上面注冊中間件的幾種方式,比如Use內部如果寫太多的代碼也不合適,所以可以自己封裝中間件,封裝完成之后可以像內置中間件一樣使用UseXxxx的方式注冊,

本例目標要完成一個中間件可以檢測HTTP請求方法,僅接受GETHEAD方法,步驟如下:
新建一個檔案夾mymiddleware,新建檔案HttpMethodCheckMiddleware.cs,中間件封裝需要實作兩個方法:

  • HttpMethodCheckMiddleware: 建構式,引數型別為RequestDelegate
  • Invoke: 中間件調度函式,引數型別為HttpContext,回傳型別為Task

檔案內容如下:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace middleware.mymiddleware
{
    /// <summary>
    /// 請求方法檢查中間件,僅處理HEAD和GET方法
    /// </summary>
    public class HttpMethodCheckMiddleware
    {
        private readonly RequestDelegate _next;

        /// <summary>
        /// 構造方法,必須有的
        /// </summary>
        /// <param name="requestDelegate">下一個中間件</param>
        public HttpMethodCheckMiddleware(RequestDelegate requestDelegate)
        {
            this._next = requestDelegate;
        }

        /// <summary>
        /// 中間件調度方法
        /// </summary>
        /// <param name="context">HTTP背景關系</param>
        /// <returns>TASK任務狀態</returns>
        public Task Invoke(HttpContext context)
        {
            // 如果符合條件,則將httpcontext傳給下一個中間件處理
            if(context.Request.Method.ToUpper().Equals(HttpMethods.Head)
                || context.Request.Method.ToUpper().Equals(HttpMethods.Get))
            {
                return _next(context);
            }

            // 否則直接回傳處理完成
            context.Response.StatusCode = 400;
            context.Response.Headers.Add("X-AllowedHTTPVerb", new[] {"GET,HEAD"});
            context.Response.ContentType = "text/plain;charset=utf-8";  // 防止中文亂碼
            context.Response.WriteAsync("只支持GET、HEAD方法");
            return Task.CompletedTask;
        }
    }
}

這樣就可以直接在Startup中使用了:

app.UseMiddleware<HttpMethodCheckMiddleware>();

還可以撰寫一個擴展類,封裝成類似內置中間件的方式UseXxx,新建CustomMiddlewareExtension.cs檔案,內容如下:

using Microsoft.AspNetCore.Builder;

namespace middleware.mymiddleware
{
    /// <summary>
    /// 封裝中間件的擴展類
    /// </summary>
    public static class CustomMiddlewareExtension
    {
        /// <summary>
        /// 添加HttpMethodCheckMiddleware中間件的擴展方法
        /// </summary>
        public static IApplicationBuilder UseHttpMethodCheckMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<HttpMethodCheckMiddleware>();
        }
    }
}

現在就可以直接呼叫UseHttpMethodCheckMiddleware注冊中間件了.

執行結果截圖省略,

疑問:那個CustomMiddlewareExtension也沒見參考,怎么就可以直接使用app.UseHttpMethodCheckMiddleware方法了?
有的可能和我一樣,c#都沒有學明白就直接開始擼dotnet了,看到這一臉懵逼,不過經過一番搜索,原來這是c#中對已有類或介面進行方法擴展的一種方式,參考C#編程指南,

內置路由

這一節先當了解,暫時用處不大,學完也會忘掉

先簡單看一下ASP.NET core內置的路由方式(直接上startup.cs代碼內容):

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace routing
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection servcies)
        {

        }

        public void Configure(IApplicationBuilder app)
        {
            // 新建一個路由處理器
            var trackPackageRouteHandler = new RouteHandler(context =>
            {
                var routeValues = context.GetRouteData().Values;
                return context.Response.WriteAsync($"Hello! Route values: {string.Join(", ", routeValues)}");
            });
            var routeBuilder = new RouteBuilder(app, trackPackageRouteHandler);
            // 通過MapRoute添加路由模板
            routeBuilder.MapRoute("Track Package Route", "package/{opration}/{id:int}");
            routeBuilder.MapGet("hello/{name}", context =>
            {
                var name = context.GetRouteValue("name");
                return context.Response.WriteAsync($"Hi, {name}!");
            });
            var routes = routeBuilder.Build();
            app.UseRouter(routes);
        }
    }
}

從代碼中可知,需要先創建一個路由處理器trackPackageRouteHandler,然后通過RouteBuilderapptrackPackageRouteHandler系結,而且需要添加一個匹配模板,最后將生成的路由器添加到app中,
其中添加路由匹配模板是使用了不同的方法:

  • MapRoute: 這個方法設定一個路由模板,匹配成功的請求會路由到trackPackageRouteHandler;
  • MapGet: 這個方法添加的模板,只適用于GET請求方式,并且第二個引數可以指定處理請求的邏輯;

上面設定路由的方式過于復雜,所以一般情況下通常使用MVC將對應的URL請求路由到Controller中處理,簡化路由規則,

Controller和Action

在開始MVC路由之前,先來學習一下ControllerAction他們的關系以及如何創建,

Controller一般是一些public類,Action對應Controller中的public函式,所以他們的關系也很明了:一個Controller可以有多個Action

Controller如何創建,默認情況下滿足下面的條件就可以作為一個Controller

  • 在專案根目錄的Controllers
  • 類名稱以Controller結尾并繼承自Controller,或被[Controller]標記的類
  • 共有類
  • 沒有被[NotController]被標記

例如一個Contoller的常用模式如下:

using Microsoft.AspNetCore.Mvc;
public class HomeController : Controller
{
    //...
}

Action就不需要許多條條框框了,只要寫在Controller中的方法函式都會被當成Action對待,如果不想一個函式被當做Action則需要添加[NotAction]標記,

留待測驗:

  1. 如果同時添加[Controller][NotController]會發生什么狀況?是誰在最后誰生效嗎還是報錯?
  2. 是不是只需要滿足Controller后綴就可以了,不一定非得繼承Controller,繼承他只是為了使用一些已經打包好的父類函式,

MVC路由

首先創建一個HomeController測驗路由用,需要創建到Controllers目錄下:

using Microsoft.AspNetCore.Mvc;

namespace routing.Controllers
{
    public class HomeController: Controller
    {
        public string Index()
        {
            return "Hello from HomeController.Index";
        }
    }
}

.net core 2.0.net core 3.0創建路由的方式有所不同,現在分開說一下,先說一下舊的方式,

先在ConfigureServices中注冊MVC服務,然后Configure中配置路由模板:

public void ConfigureServices(IServiceCollection service)
{
    // 注冊服務
    service.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    if(env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    // 路由模板
    app.UseMvc(routes =>
    {
        routes.MapRoute(template: "{controller}/{action}/{id?}", 
                        defaults: new {controller = "Home", action = "Index"});
    });

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}

但是放到dotnet3里面是會報錯的:

MVCRouteStartup.cs(23,13): warning MVC1005: Using 'UseMvc' to configure MVC is not supported while using Endpoint Routing. To continue using 'UseMvc', please set 'MvcOptions.EnableEndpointRouting = false' inside 'ConfigureServices'. 

提示UseMvc不支持Endpoint Routing,通過查資料(stackoverflow)找到原因,說的很清楚:2的時候MVC路由基于IRoute,3改成Endpoint了,官方推薦將UseMVC使用UseEndpoiont替換:

app.UseRouting(); // 必須寫,如果使用了UseStaticFiles要放在他之前
app.UseEndpoints(endpoionts =>
{
    endpoionts.MapControllerRoute(name: "MVC TEST ROUTE", 
                                pattern: "{controller}/{action}/{id?}",
                                defaults: new {controller = "Home", action = "Index"});
});

ConfigureServices中注冊MVC也有兩種方式:

services.AddMVC();

service.AddControllersWithViews();
service.AddRazorPages();

當然,如果不想把UseMap去掉,那么可以按照報錯的提示在AddMVC的時候配置一下引數禁用EndpointRoute

services.AddMvc(options => options.EnableEndpointRouting = false);

然后就可以跑起來了:

好,扯了半天報錯,還是回到mvc路由上,上面是簡單演示了一下在Startup中如何創建路由,其實mvc路由有兩種定義方式:

  • 約定路由:上面使用的方式就是約定路由,需要在Startup中配置;
  • 特性路由:使用[Route]直接對controlleraction進行標記;

修改HomeController加上路由標記:

using Microsoft.AspNetCore.Mvc;

namespace routing.Controllers
{
    [Route("h")]
    [Route("[controller]")]
    public class HomeController: Controller
    {
        [Route("")]
        [Route("[action]")]
        public string Index()
        {
            return "Hello from HomeController.Index";
        }
    }
}

通過[controller][action]就可以動態的指代homeindex(路徑不區分大小寫),這樣如果路由會隨著類名或方法名稱的改變自動調整,

并且可以看出,可以多個[Route]標記重疊使用,例如訪問/h/home/index效果一樣:

通過實驗可以看出,特性路由會覆寫掉約定路由

先總結這些吧,突然發現asp.net core這個東西還是挺先進的,比如依賴注入,Startup中的函式多數都是interface,為什么直接對介面操作就可以改變一些東西或者讓我們可以自己注冊一個中間件到app上,然后為什么都不需要參考或者實體化就可以直接用app呼叫了,這都和依賴注入有關系吧,還有介面的設計理念也好像和其他語言的不太一樣,神奇了,

實驗代碼

放到了github上,部分代碼好像丟失了,不過應該不要緊,

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/85.html

標籤:ASP.NET MVC

上一篇:ASP.NET MVC+Echarts繪制統計圖表

下一篇:asp.net mvc 微信公眾號開發 介面配置資訊,n g r o k穿透,vs除錯

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more