1. 程式人生 > 實用技巧 >spring boot 遷移至asp.net core

spring boot 遷移至asp.net core

asp.net core類似於spring boot,內建了一個kerstral web伺服器,所以可以直接通過dotnet啟動,然後訪問。

本文著重於.net操作mongodb的過程

框架新增mongoHelper

因為EFcore是不支援mongoHelper,所以只能通過MongoClient來訪問資料庫

首先框架中新增mongoHelper類,mongoHelper通過泛型來實現增刪改查,資料庫配置在appSetting.json中,然後把mongoHelper注入容器

public static class MongoServiceCollectionExtension
    {
        
public static void AddMongoDb(this IServiceCollection services, IConfiguration configuration) { services.Configure<MongoOption>(configuration.GetSection("MongoOption")); services.AddSingleton<MongoClientHelper>(); services.AddSingleton<MongoHelper>(); } }
public class MongoHelper
    {
        private IMongoDatabase _dataBase;

        private MongoClient _client;

        public MongoHelper(MongoClientHelper clienthelper, IOptions<MongoOption> option)
        {
            _client = clienthelper.GetMongoClient();
            _dataBase = _client.GetDatabase(option.Value.DefaultDataBase);
        }

        
public void SwitchDataBase(string dataBaseName) { _dataBase = _client.GetDatabase(dataBaseName); } private IMongoCollection<T> GetCollection<T>() { return _dataBase.GetCollection<T>(typeof(T).Name); } private IMongoCollection<BsonDocument> GetAggregrationCollection<T>() { return _dataBase.GetCollection<BsonDocument>(typeof(T).Name); } }

下面來詳細說說遇到的坑

1. 獲取不到配置的database

一開始的配置如下,然後發現最後獲取的database是預設的admin,並不是配置的mydb

// mongoDb配置
  "MongoOption": {
    "MongoHost": "mongodb://me:[email protected]:27017",
    "DefaultDataBase": "mydb"
  },

網上查到一句話

最終把db名字加到了後面

// mongoDb配置
  "MongoOption": {
    "MongoHost": "mongodb://me:[email protected]:27017/mydb",
  },

2. 讀取表資料報錯,不能將string轉換成DateTime

由於mongo的特性,不管我插入什麼資料都行,只要把對應的model改成你想要的就行。但是讀取的時候我們必須指定一個model,那麼假如這個model以前插入過資料,然後被修改了又插入過資料,當你讀取的時候就會報錯。我這邊有個欄位原來是string型別的,用了一段時間後,被改成了DateTime型別。當我使用mongo的find方法時,他就報錯了string不能轉換成datetime。

然後我嘗試著增加建構函式,或者修改setter方法,但是依然沒有用

於是我在mongo裡面增加了一個方法,可以看到上圖中有2個GetCollection方法,第二個是給聚合函式用的,

        /// <summary>
        /// 根據條件查詢資料
        /// </summary>
        public List<T> Get<T>(FilterDefinition<T> filter)
        {
            return GetCollection<T>().Find(filter).ToList();
        }

        /// <summary>
        /// 聚合查詢表T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pipeline"></param>
        /// <returns></returns>
        public async Task<List<BsonDocument>> AggregateAsync<T>(PipelineDefinition<BsonDocument, BsonDocument> pipeline)
        {
            return (await GetAggregrationCollection<T>().AggregateAsync(pipeline)).ToList();
        }

第二個查找出來的是BsonDocument型別的list,需要轉換成對應的model list

    protected List<TaskCats> ConvertAggregateResultToTaskCats(List<BsonDocument> queryResults)
        {
            if (!queryResults.Any())
                return null;
            return queryResults.Select(result =>
            {
                // 歷史遺留問題,reportingTime可能為空,為string,為datetime
                //var reportingTime = result["reportingTime"];
                var reportingTime = result.GetValue("reportingTime");
                return new TaskCats(
                    result["adAccount"].ToString(),
                    Convert.ToDateTime(result["reportedDate"]),
                    reportingTime.ToString() == "BsonNull" ? Convert.ToDateTime("1990-11-11") : Convert.ToDateTime(reportingTime),
                    Convert.ToDateTime(result["startDate"]),
                    result["taskId"].ToString(),
                    result.GetValue("description", null)?.ToString(),
                    result.GetValue("weekday", null)?.ToString(),
                    Convert.ToDouble(result["workingHours"]),
                    result.GetValue("BUName", null)?.ToString(),
                    result.GetValue("priority", null)?.ToString(),
                    result.GetValue("projectName", null)?.ToString(),
                    result.GetValue("otherProject", null)?.ToString(),
                    result["_id"].ToString());
            }).ToList();
        }

框架到此為止(最後那個轉換是在業務層實現,因為會涉及到具體的entity)

業務類實現

controller實現互動,service負責具體的操作,聯動model和entity以及dao層的mongoHelper。

這裡有一個前期資料匯入的類,比如說匯入初始管理員以及menu列表,這一塊是跟業務相關的,我把它放在了業務層。

編寫IHost的extension類,通過IServiceScope獲取注入的類物件,實現資料庫插入

        /// <summary>
        /// Initialize the mongodb data, insert menu info and admin user.
        /// </summary>
        /// <param name="host">The host</param>
        public static void InitialData(this IHost host)
        {
            using var serviceScope = host.Services.CreateScope();
            var mongoHelper = serviceScope.ServiceProvider.GetRequiredService<MongoHelper>();
            AddMenuInfo(mongoHelper);
            if (!IsDefaultUserExsit(mongoHelper))
            {
                AddDefaultUser(mongoHelper);
            }
        }    

配置validation

使用FluentValidation:https://www.cnblogs.com/lwqlun/p/10311945.html

返回badRequest跟controller格式一致

這個Extension是屬於框架類,這邊只是展示用

一些問題

1. 因為spring boot預設會給表增加_class欄位用於對映,但是.net使用mongoClient並不需要這個欄位,假如不定義就會報錯。暫時沒有找到很好的解決辦法,定義了一個_class屬性。

2. 對於Nlog,路徑一定要用/,不能用\. 因為linux下會找不到路徑,導致所有的log都記錄在根目錄下面

3. MongoDb時區問題

[BsonDateTimeOptions(Kind = DateTimeKind.Local)]

很多攻略說新增這個特性,其實這個特性的意思是跟jvm設定一樣的,插入的時候,mongo驅動會自動把時間轉換成0時區的時間,存入資料庫,然後你會發現資料庫中的資料跟實際的比對確實是少了8個小時。查詢的時候,查出來的資料,mongo驅動會自動再加上8小時,所以你使用的時候就感覺不出有問題。假如你需要資料庫裡面儲存的時間跟實際的一致,那麼不管你插入還是查詢都必須加8小時(對於mongo的insert和find是這樣,但是aggregate方法不需要加)。