主頁 > .NET開發 > .NET應用系統的國際化-基于Roslyn抽取詞條、更新代碼

.NET應用系統的國際化-基于Roslyn抽取詞條、更新代碼

2023-03-19 13:47:21 .NET開發

上篇文章我們介紹了

VUE+.NET應用系統的國際化-多語言詞條服務

系統國際化改造整體設計思路如下:

  1. 提供一個工具,識別前后端代碼中的中文,形成多語言詞條,按語言、界面、模塊統一管理多有的多語言詞條
  2. 提供一個翻譯服務,批量翻譯多語言詞條
  3. 提供一個詞條服務,支持后端代碼在運行時根據用戶登錄的語言,動態獲取對應的多語言文本
  4. 提供前端多語言JS生成服務,按界面動態生成對應的多語言JS檔案,方便前端VUE檔案使用,
  5. 提供代碼替換工具,將VUE前端代碼中的中文替換為$t("詞條ID"),后端代碼中的中文替換為TermService.Current.GetText("詞條ID")

今天,我們在上篇文章的基礎上,繼續介紹基于Roslyn抽取詞條、更新代碼,

一、業務背景

先說一下業務背景,后端.NET代碼中存在大量的中文提示和例外訊息,甚至一些中文回傳值文本,

這些中文文字都需要識別出來,抽取為多語言詞條,同時將代碼替換為呼叫多語言詞條服務獲取翻譯后的文本,

例如:

private static void CheckMd5(string fileName, string md5Data)
{
      string md5Str = MD5Service.GetMD5(fileName);
      if (!string.Equals(md5Str, md5Data, StringComparison.OrdinalIgnoreCase))
      {
           throw new CustomException(PackageExceptionConst.FileMd5CheckFailed, "服務包檔案MD5校驗失敗:" + fileName);
      }
}

代碼中需要將“服務包檔案MD5校驗失敗”這個文本做多語言改造,

這里通過呼叫多語言詞條服務I18NTermService,根據執行緒背景關系中設定的語言,獲取對應的翻譯文本,例如以下代碼:

var text=T.Core.I18N.Service.TermService.Current.GetTextFormatted("詞條ID""默認文本"); 

throw new CustomException(PackageExceptionConst.FileMd5CheckFailed, text + fileName);

以上背景下,我們準備使用Roslyn技術對代碼進行中文掃描,對掃描出來的文本,做詞條抽取、代碼替換,

二、使用Roslyn技術對代碼進行中文掃描

首先,我們先定義好代碼中多語言詞條的掃描結果類TermScanResult

 1  [Serializable]
 2     public class TermScanResult
 3     {
 4         public Guid Id { get; set; }
 5         public string OriginalText { get; set; }
 6 
 7         public string ChineseText { get; set; }
 8 
 9         public string SlnName { get; set; }
10 
11         public string ProjectName { get; set; }
12 
13         public string ClassFile { get; set; }
14 
15         public string MethodName { get; set; }
16 
17         public string Code { get; set; }
18 
19         public I18NTerm I18NTerm { get; set; }
20 
21         public string SlnPath { get; set; }
22 
23         public string ClassPath { get; set; }
24 28         public string SubSystemCode { get; set; }
29 
30         public override string ToString()
31         {
32             return Code;
33         }
34     }

上述代碼中SubSystemCode是一個業務管理維度,大家忽略即可,

我們會以sln解決方案為單位,掃描代碼中的中文文字,

以下是具體的實作代碼

public async Task<List<TermScanResult>> CheckSln(string slnPath, System.ComponentModel.BackgroundWorker backgroundWorker, SubSystemFile subSystemFiles, string subSystem)
{
            var slnFile = new FileInfo(slnPath);
            var results = new List<TermScanResult>();

            MSBuildHelper.RegisterMSBuilder();
            var solution = await MSBuildWorkspace.Create().OpenSolutionAsync(slnPath);

            var subSystemInfo = subSystemFiles?.SubSystemSlnMappings.FirstOrDefault(w => w.SlnName.Select(s => s += ".sln").Contains(slnFile.Name.ToLower()));

            if (solution.Projects != null && solution.Projects.Count() > 0)
            {
                foreach (var project in solution.Projects.ToList())
                {
                    backgroundWorker.ReportProgress(10, $"掃描Project: {project.Name}");
                    var documents = project.Documents.Where(x => x.Name.Contains(".cs"));

                    if (project.Name.ToLower().Contains("test"))
                    {
                        continue;
                    }
                    var codeReplace = new CodeReplace();
                    foreach (var document in documents)
                    {
                        var tree = await document.GetSyntaxTreeAsync();
                        var root = tree.GetCompilationUnitRoot();
                        if (root.Members == null || root.Members.Count == 0) continue;
                        //member
                        var classDeclartions = root.DescendantNodes().Where(i => i is ClassDeclarationSyntax);

                        foreach (var classDeclare in classDeclartions)
                        {
                            var programDeclaration = classDeclare as ClassDeclarationSyntax;
                            if (programDeclaration == null) continue;

                            foreach (var memberDeclarationSyntax in programDeclaration.Members)
                            {
                                foreach (var item in GetLiteralStringExpression(memberDeclarationSyntax))
                                {
                                    var statementCode = item.Item1;
                                    foreach (var syntaxNode in item.Item3)
                                    {
                                        ExpressionSyntaxParser expressionSyntaxParser = new ExpressionSyntaxParser();
                                        var text = "";
                                        var expressionSyntax = expressionSyntaxParser
                                            .GetExpressionSyntaxVerifyRule(syntaxNode as ExpressionSyntax, statementCode);
                                        if (expressionSyntax != null)
                                        {
                                            // 排除
                                            if (expressionSyntaxParser.IsExcludeCaller(expressionSyntax, statementCode))
                                            {
                                                continue;
                                            }

                                            text = expressionSyntaxParser.GetExpressionSyntaxOriginalText(expressionSyntax, statementCode);
                                            if (expressionSyntax is Microsoft.CodeAnalysis.CSharp.Syntax.InterpolatedStringExpressionSyntax)
                                            {
                                                text = expressionSyntaxParser.GetExpressionSyntaxOriginalText(expressionSyntax, statementCode);

                                                if (expressionSyntax is Microsoft.CodeAnalysis.CSharp.Syntax.LiteralExpressionSyntax)
                                                {
                                                    if (!expressionSyntax.IsKind(SyntaxKind.StringLiteralExpression))
                                                    {
                                                        continue;
                                                    }
                                                    text = expressionSyntax.NormalizeWhitespace().ToString();
                                                }
                                            }
                                        }
                                        if (CheckChinese(text) == false) continue;
                                        if (string.IsNullOrWhiteSpace(text)) continue;
                                        if (string.IsNullOrWhiteSpace(text.Replace("\"", "").Trim())) continue;

                                        results.Add(new TermScanResult()
                                        {
                                            Id = Guid.NewGuid(),
                                            ClassPath = programDeclaration.SyntaxTree.FilePath,
                                            SlnPath = slnPath,
                                            OriginalText = text.Replace("\"", "").Trim(),
                                            ChineseText = text,
                                            SlnName = slnFile.Name,
                                            ProjectName = project.Name,
                                            ClassFile = programDeclaration.Identifier.Text,
                                            MethodName = item.Item2,
                                            Code = statementCode,
                                            SubSystemCode = subSystem
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }

     return results;
}

上述代碼中,我們先使用MSBuilder編譯,構建 sln解決方案

MSBuildHelper.RegisterMSBuilder();
var solution = await MSBuildWorkspace.Create().OpenSolutionAsync(slnPath);

然后遍歷solution下的各個Project中的class類

foreach (var project in solution.Projects.ToList())
var documents = project.Documents.Where(x => x.Name.Contains(".cs"));

然后遍歷類中宣告、成員、方法中的每行代碼,通過正則運算式識別是否有中文字符

public static bool CheckChinese(string strZh)
{
            Regex re = new Regex(@"[\u4e00-\u9fa5]+");
            if (re.IsMatch(strZh))
            {
                return true;
            }
            return false;
}

如果存在中文字符,作為掃描后的結果,識別為多語言詞條

results.Add(new TermScanResult()
{
        Id = Guid.NewGuid(),
        ClassPath = programDeclaration.SyntaxTree.FilePath,
        SlnPath = slnPath,
        OriginalText = text.Replace("\"", "").Trim(),
        ChineseText = text,
        SlnName = slnFile.Name,
        ProjectName = project.Name,
        ClassFile = programDeclaration.Identifier.Text,
        MethodName = item.Item2,
        Code = statementCode,        //管理維度                                  
        SubSystemCode = subSystem    //管理維度
});

TermScanResult中沒有對詞條屬性賦值,

public I18NTerm I18NTerm { get; set; }

下一篇文章的代碼中,我們會通過多語言翻譯服務,將翻譯后的文本放到I18NTerm 屬性中,作為多語言詞條,

三、代碼替換

代碼替換這塊邏輯中,我們設計了一個類SourceWeaver,對上一步的代碼掃描結果,進行代碼替換

CodeScanReplace這個方法中完成了代碼的二次掃描和替換
 /// <summary>
    /// 源代碼替換服務
    /// </summary>
    public class SourceWeaver
    {
        List<CommonTermDto> commonTerms = new List<CommonTermDto>();
        List<CommonTermDto> commSubTerms = new List<CommonTermDto>();

        public SourceWeaver()
        {
            commonTerms = JsonConvert.DeserializeObject<List<CommonTermDto>>(File.ReadAllText("comm_data.json"));
            commSubTerms = JsonConvert.DeserializeObject<List<CommonTermDto>>(File.ReadAllText("comm_sub_data.json"));
        }
        public async Task CodeScanReplace(Tuple<List<I18NTerm>, List<TermScanResult>> result, System.ComponentModel.BackgroundWorker backgroundWorker)
        {
            try
            {
                backgroundWorker.ReportProgress(0, "正在對代碼進行替換.");
                var termScanResultGroupBy = result.Item2.GroupBy(g => g.SlnName);
                foreach (var termScanResult in termScanResultGroupBy)
                {
                    var termScan = termScanResult.FirstOrDefault();
                    MSBuildHelper.RegisterMSBuilder();
                    var solution = await MSBuildWorkspace.Create().OpenSolutionAsync(termScan.SlnPath).ConfigureAwait(false);
                    if (solution.Projects.Any())
                    {
                        foreach (var project in solution.Projects.ToList())
                        {
                            if (project.Name.ToLower().Contains("test"))
                            {
                                continue;
                            }
                            var projectTermScanResults = result.Item2.Where(f => f.ProjectName == project.Name);

                            var documents = project.Documents.Where(x =>
                            {
                                return x.Name.Contains(".cs") && projectTermScanResults.Any(f => $"{f.ClassPath}" == x.FilePath);
                            });

                            foreach (var document in documents)
                            {
                                var tree = await document.GetSyntaxTreeAsync().ConfigureAwait(false);
                                var root = tree.GetCompilationUnitRoot();
                                if (root.Members.Count == 0) continue;

                                var classDeclartions = root.DescendantNodes()
                                    .Where(i => i is ClassDeclarationSyntax);
                                List<MemberDeclarationSyntax> syntaxNodes = new List<MemberDeclarationSyntax>();
                                foreach (var classDeclare in classDeclartions)
                                {
                                    if (!(classDeclare is ClassDeclarationSyntax programDeclaration)) continue;
                                    var className = programDeclaration.Identifier.Text;

                                    foreach (var method in programDeclaration.Members)
                                    {
                                        if (method is ConstructorDeclarationSyntax)
                                        {
                                            syntaxNodes.Add((ConstructorDeclarationSyntax)method);
                                        }
                                        else if (method is MethodDeclarationSyntax)
                                        {
                                            syntaxNodes.Add((MethodDeclarationSyntax)method);
                                        }
                                        else if (method is PropertyDeclarationSyntax)
                                        {
                                            syntaxNodes.Add(method);
                                        }
                                        else if (method is FieldDeclarationSyntax)
                                        {
                                            // 注:常量不支持
                                            syntaxNodes.Add(method);
                                        }
                                    }
                                }

                                var terms = termScanResult.Where(
                                    f => f.ProjectName == document.Project.Name && f.ClassPath == document.FilePath).ToList();
                                backgroundWorker.ReportProgress(10, $"正在檢查{document.FilePath}檔案.");
                                ReplaceNodesAndSave(root, syntaxNodes, terms, result, backgroundWorker, document.Name);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogUtils.LogError(string.Format("例外型別:{0}\r\n例外訊息:{1}\r\n例外資訊:{2}\r\n",
                    ex.GetType().Name, ex.Message, ex.StackTrace));
                backgroundWorker.ReportProgress(0, ex.Message);
            }
        }

        public async void ReplaceNodesAndSave(SyntaxNode classSyntaxNode, List<MemberDeclarationSyntax> syntaxNodes, IEnumerable<TermScanResult> terms, Tuple<List<I18NTerm>, List<TermScanResult>> result,
            System.ComponentModel.BackgroundWorker backgroundWorker, string className)
        {

            {//check pro是否存在詞條
                if (AppConfig.Instance.IsCheckTermPro)
                {
                    backgroundWorker.ReportProgress(15, $"詞條驗證中.");
                    var termsCodes = terms.Select(f => f.I18NTerm.Code).ToList();
                    var size = 100;
                    var p = (result.Item2.Count() + size - 1) / size;

                    using DBHelper dBHelper = new DBHelper();
                    List<I18NTerm> items = new List<I18NTerm>();
                    for (int i = 0; i < p; i++)
                    {
                        var list = termsCodes
                            .Skip(i * size).Take(size);
                        Thread.Sleep(10);
                        var segmentItems = await dBHelper.GetTermsAsync(termsCodes).ConfigureAwait(false);
                        items.AddRange(segmentItems);
                    }

                    List<TermScanResult> termScans = new List<TermScanResult>();
                    foreach (var term in terms)
                    {
                        if (items.Any(f => f.Code == term.I18NTerm.Code))
                        {
                            termScans.Add(term);
                        }
                        else
                        {
                            backgroundWorker.ReportProgress(20, $"詞條{term.OriginalText}未匯入到詞條庫,該詞條將忽略替換.");
                        }
                    }
                    terms = termScans;
                }
            }

            var newclassDeclare = classSyntaxNode;
            newclassDeclare = classSyntaxNode.ReplaceNodes(syntaxNodes,
                    (methodDeclaration, _) =>
                    {                     
                        MemberDeclarationSyntax newMemberDeclarationSyntax = methodDeclaration;
                        var className = ((ClassDeclarationSyntax)newMemberDeclarationSyntax.Parent).Identifier.Text;
                        List<StatementSyntax> statementSyntaxes = new List<StatementSyntax>();

                        switch (newMemberDeclarationSyntax)
                        {
                            case ConstructorDeclarationSyntax:
                                {
                                    var blockSyntax = (newMemberDeclarationSyntax as ConstructorDeclarationSyntax).NormalizeWhitespace().Body;
                                    if (blockSyntax == null)
                                    {
                                        break;
                                    }
                                    foreach (var statement in blockSyntax.Statements)
                                    {
                                        var nodeStatement = statement.DescendantNodes();

                                        statementSyntaxes.Add(new CodeReplace().ReplaceStatementNodes(statement,
                                            new ExpressionSyntaxParser().LiteralStringExpression(nodeStatement), terms, commonTerms, commSubTerms));
                                    }

                                    break;
                                }

                            case MethodDeclarationSyntax:
                                {
                                    var blockSyntax = (methodDeclaration as MethodDeclarationSyntax).NormalizeWhitespace().Body;
                                    if (blockSyntax == null)
                                    {
                                        break;
                                    }
                                    foreach (var statement in blockSyntax.Statements)
                                    {
                                        var nodeStatement = statement.DescendantNodes();
                                        statementSyntaxes.Add(new CodeReplace().ReplaceStatementNodes(statement,
                                               new ExpressionSyntaxParser().LiteralStringExpression(nodeStatement), terms, commonTerms, commSubTerms));
                                    }

                                    break;
                                }

                            case PropertyDeclarationSyntax:
                                {
                                    var propertyDeclarationSyntax = newMemberDeclarationSyntax as PropertyDeclarationSyntax;

                                    var nodeStatement = propertyDeclarationSyntax.DescendantNodes();

                                    return new CodeReplace().ReplacePropertyNodes(newMemberDeclarationSyntax as PropertyDeclarationSyntax,
                                        new ExpressionSyntaxParser().LiteralStringExpression(nodeStatement), terms, commonTerms, commSubTerms);
                                }

                            case FieldDeclarationSyntax:
                                {
                                    var fieldDeclarationSyntax = newMemberDeclarationSyntax as FieldDeclarationSyntax;
                                    var nodeStatement = fieldDeclarationSyntax.DescendantNodes();
                                    return new CodeReplace().ReplaceFiledNodes(fieldDeclarationSyntax,
                                           new ExpressionSyntaxParser().LiteralStringExpression(nodeStatement), terms, commonTerms, commSubTerms);
                                }
                        }
                        backgroundWorker.ReportProgress(50, $"決議并對類檔案{className}中的方法做陳述句替換.");
                        // 替換方法內部
                        if (newMemberDeclarationSyntax is MethodDeclarationSyntax)
                        {
                            return new CodeReplace().ReplaceMethodDeclaration(newMemberDeclarationSyntax as MethodDeclarationSyntax, statementSyntaxes);
                        }
                        else if (newMemberDeclarationSyntax is ConstructorDeclarationSyntax)
                        {
                            return new CodeReplace().ReplaceConstructorDeclaration(newMemberDeclarationSyntax as ConstructorDeclarationSyntax, statementSyntaxes);
                        }
                        return newMemberDeclarationSyntax;
                    });

            var sourceStr = newclassDeclare.NormalizeWhitespace().GetText().ToString();
            File.WriteAllText(newclassDeclare.SyntaxTree.FilePath, sourceStr);
            backgroundWorker.ReportProgress(100, $"完成{className}的替換.");
        }
    }

關鍵的代碼語意替換的實作代碼:

 public StatementSyntax ReplaceStatementNodes(StatementSyntax statement, List<ExpressionSyntax> expressionSyntaxes, IEnumerable<TermScanResult> terms
            , List<CommonTermDto> commonTerms, List<CommonTermDto> commSubTerms)
        {
            var statementSyntax = statement.ReplaceNodes(expressionSyntaxes, (syntaxNode, _) =>
            {
                var statementStr = statement.NormalizeWhitespace().ToString();

                var argumentLists = statement.DescendantNodes().
                                               OfType<InvocationExpressionSyntax>();
                ExpressionSyntaxParser expressionSyntaxParser = new ExpressionSyntaxParser();
                return expressionSyntaxParser.ExpressionSyntaxTermReplace(syntaxNode, statementStr, terms, commonTerms, commSubTerms);

            });

            return statementSyntax;
        }

這里,我們抽象了一個ExpressionSyntaxParser 類,負責替換代碼:

T.Core.I18N.Service.TermService.Current.GetTextFormatted
 public ExpressionSyntax ExpressionSyntaxTermReplace(ExpressionSyntax syntaxNode, string statementStr, IEnumerable<TermScanResult> terms
            , List<CommonTermDto> commonTerms, List<CommonTermDto> commSubTerms)
        {
            var expressionSyntax = GetExpressionSyntaxVerifyRule(syntaxNode, statementStr);
            var originalText = GetExpressionSyntaxOriginalText(expressionSyntax, statementStr);

            var I18Expr = "";
            var interpolationSyntaxes = syntaxNode.DescendantNodes().OfType<InterpolationSyntax>();         
            var term = terms.FirstOrDefault(i => i.ChineseText == originalText);

            if (term == null)
                return syntaxNode;
            string termcode = term.I18NTerm.Code;
if (syntaxNode is InterpolatedStringExpressionSyntax)
            {
                if (interpolationSyntaxes.Count() > 0)
                {
                    var parms = "";
                    foreach (var item in interpolationSyntaxes)
                    {
                        parms += $",{item.ToString().TrimStart('{').TrimEnd('}')}";
                    }
                    I18Expr = "$\"{T.Core.I18N.Service.TermService.Current.GetTextFormatted(\"" + termcode + "\", " + originalText + parms + ")}\"";
                    var token1 = SyntaxFactory.Token(default, SyntaxKind.StringLiteralToken, I18Expr, "", default);
                    return SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, token1);
                }
                else
                {

                    var startToken = SyntaxFactory.Token(SyntaxKind.InterpolatedStringStartToken);
                    if ((syntaxNode as InterpolatedStringExpressionSyntax).StringStartToken.Value =https://www.cnblogs.com/tianqing/archive/2023/03/19/= startToken.Value)
                    {
                        // 如果本身有"$"
                        I18Expr = "$\"{T.Core.I18N.Service.TermService.Current.GetText(\"" + termcode + "\"," + originalText + ")}";
                    }
                    else
                    {
                        // 如果沒有"$"
                        I18Expr = "$\"{T.Core.I18N.Service.TermService.Current.GetText(\"" + termcode + "\",\\teld\"" + originalText + "\")}";
                        I18Expr = I18Expr.Replace("\\teld", "$");
                    }
                }
            }
            else
            {
                I18Expr = "$\"{T.Core.I18N.Service.TermService.Current.GetText(\"" + termcode + "\"," + originalText + ")}";
            }

            var token = SyntaxFactory.Token(default(SyntaxTriviaList), SyntaxKind.InterpolatedVerbatimStringStartToken, I18Expr, "$\"", default(SyntaxTriviaList));
            var literalExpressionSyntax = SyntaxFactory.InterpolatedStringExpression(token);
            return literalExpressionSyntax;
        }
T.Core.I18N.Service.TermService這個就是多語言詞條服務類,這個類中提供了一個GetText的方法,通過詞條編號,獲取多語言文本,

代碼完成替換后,打開VS,對工程參考多語言詞條服務的Nuget包/dll,重新編譯代碼,手工校對替換后的代碼即可,
以上是.NET應用系統的國際化-基于Roslyn抽取詞條、更新代碼的分享,



周國慶
2023/3/19







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

標籤:.NET技术

上一篇:.NET應用系統的國際化-基于Roslyn抽取詞條、更新代碼

下一篇:能快速構建和定制網路拓撲圖的WPF開源專案-NodeNetwork

標籤雲
其他(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