CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết trên blog CFSDN này phân tích sơ lược về việc tự động cập nhật cấu hình Json trong .Net Core. Nó được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này thì nhớ like nhé.
Trước 。
Ngay từ rất sớm khi tôi đang xem khóa học bắt đầu nhanh về Asp.net Core của Jesse, tôi đã biết được điều đó trong Asp.net Về cốt lõi, nếu cấu hình Json bổ sung được thay đổi, nó hỗ trợ tự động tải lại cấu hình. Là một lập trình viên có âm mưu "làm bánh" nghiêm túc, gần đây tôi đã tìm hiểu một hệ thống blog và tôi cũng muốn tạo một hệ thống blog đó. có thể tự động cập nhật như thế này. configureSource sử dụng Mysql làm nguồn dữ liệu nên mình đã click vào mã nguồn của hàm mở rộng AddJsonFile và thấy rằng nó khá thú vị. Bài viết này sẽ nói sơ qua về Json. ReloadOnChange của config được triển khai như thế nào? Trong quá trình tìm hiểu ReloadOnChange, chúng ta cũng sẽ tìm hiểu về Configuration:grin:, hy vọng nó sẽ hữu ích cho các bạn.
?
1
2
3
4
5
6
7
|
công cộng
tĩnh
IWebHostBuilder TạoWebHostBuilder(
sợi dây
[] đối số) =>
WebHost.CreateDefaultBuilder(đối số)
.ConfigureAppConfiguration(tùy chọn =>
{
tùy chọn.AddJsonFile(
"appsettings.json"
,không bắt buộc:
ĐÚNG VẬY
,tải lạiKhiThay Đổi:
ĐÚNG VẬY
);
})
.UseStartup();
|
Nếu nguồn dữ liệu json được định cấu hình trong lõi Asp.net, việc đặt thuộc tính loadingOnChange thành true có thể tự động cập nhật cấu hình khi tệp thay đổi. Trong blog này, trước tiên chúng ta sẽ xem qua mã nguồn của nó. có thể vẫn còn hơi bối rối. Nếu bạn bối rối, đừng hoảng sợ. Tôi sẽ sắp xếp hợp lý các mã này và đưa ra một ví dụ đơn giản. Tôi hy vọng nó sẽ hữu ích cho bạn.
Một cái nhìn vào mã nguồn.
ThêmJson 。
Trước hết, tất nhiên chúng ta bắt đầu với hàm mở rộng quen thuộc này và quá trình phát triển của nó như sau.
?
1
2
3
4
|
công cộng
tĩnh
IConfigurationBuilder AddJsonFile(
cái này
Trình xây dựng IConfigurationBuilder,
sợi dây
con đường,
bool
không bắt buộc,
bool
tải lạiKhiThay Đổi)
{
trở lại
builder.AddJsonFile((IFileProvider)
vô giá trị
, đường dẫn, tùy chọn, reloadOnChange);
}
|
Chuyển một FileProvider rỗng sang một hàm Addjson bị quá tải khác.
Gõ lên bảng đen, FileProvider của Null rất quan trọng và sẽ được kiểm tra sau: Smile:.
?
1
2
3
4
5
6
7
8
9
10
11
|
công cộng
tĩnh
IConfigurationBuilder AddJsonFile(
cái này
Trình xây dựng IConfigurationBuilder, nhà cung cấp IFileProvider,
sợi dây
con đường,
bool
không bắt buộc,
bool
tải lạiKhiThay Đổi)
{
trở lại
builder.AddJsonFile((Hành động) (s =>
{
s.FileProvider = nhà cung cấp;
s.Path = đường dẫn;
s.Optional = tùy chọn;
s.ReloadOnChange = reloadOnChange;
s.ResolveFileProvider();
}));
}
|
Phát triển các tham số đến thành Hành động và gán chúng cho các thuộc tính của JsonConfigurationSource.
?
1
2
3
4
|
công cộng
tĩnh
IConfigurationBuilder AddJsonFile(
cái này
Trình xây dựng IConfigurationBuilder, Action configureSource)
{
trở lại
builder.Thêm(configureSource);
}
|
Phương thức builder.add (hành động) cuối cùng được gọi.
?
1
2
3
4
5
6
7
|
công cộng
tĩnh
IConfigurationBuilder Thêm(
cái này
IConfigurationBuilder builder,Action configureSource)nơi TSource : IConfigurationSource,
mới
()
{
Nguồn nguồn =
mới
Nguồn();
nếu như
(cấu hình nguồn !=
vô giá trị
)
configureSource(nguồn);
trở lại
builder.Add((IConfigurationSource) nguồn);
}
|
Trong phương thức Thêm, một phiên bản Nguồn được tạo, đó là phiên bản JsonConfigurationSource, sau đó phiên bản này được chuyển với tư cách là đại biểu. Bằng cách này, chúng ta chuyển vào "appsettings.json" ở ngoài cùng, tùy chọn: true, tải lạiOnChange. : true Các tham số được áp dụng cho ví dụ này.
Cuối cùng, phiên bản này được thêm vào trình tạo. Vậy trình tạo này có thể làm gì?
Cấu hình xây dựng 。
Trình xây dựng được đề cập trước đó là ConfigurationBuilder theo mặc định. Tôi đã đơn giản hóa nó.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
công cộng
lớp học
ConfigurationBuilder: IConfigurationBuilder
{
công cộng
Nguồn IList {
lấy
; } =
mới
Danh sách();
công cộng
IConfigurationBuilder Thêm(nguồn IConfigurationSource)
{
Nguồn.Thêm(nguồn);
trở lại
cái này
;
}
công cộng
IConfigurationRoot Xây dựng()
{
nơi nhà cung cấp =
mới
Danh sách();
foreach
(là nguồn
TRONG
Nguồn)
{
nhà cung cấp var = source.Build(
cái này
);
providers.Add(nhà cung cấp);
}
trở lại
mới
ConfigurationRoot(nhà cung cấp);
}
}
|
Như bạn có thể thấy, có một loại bộ sưu tập Nguồn trong trình tạo này. Nguồn này có thể lưu bất kỳ Nguồn nào triển khai IConfigurationSource. JsonConfigurationSource đã thảo luận trước đó triển khai giao diện này bao gồm MemoryConfigurationSource, XmlConfigureSource, CommandLineConfigurationSource, v.v.
Ngoài ra, nó còn có một phương thức xây dựng rất quan trọng. Phương thức xây dựng này cũng được gọi khi phương thức WebHostBuilder thực thi quá trình xây dựng. Đừng hỏi tôi phương thức WebHostBuilder.builder làm gì: joy:.
?
1
2
3
4
|
công cộng
tĩnh
vô hiệu
Chủ yếu(
sợi dây
[] đối số)
{
CreateWebHostBuilder(đối số).Build().Run();
}
|
Phương thức Builder của mỗi Nguồn được gọi trong phương thức configureBuilder. Thứ chúng ta vừa truyền vào là JsonConfigurationSource, vì vậy chúng ta cần xem trình tạo JsonSource làm gì.
Bạn có bối rối trước những trình tạo này ở đây không? Đừng hoảng sợ. Trong bài viết tiếp theo, tôi sẽ giải thích cách tùy chỉnh một configureSoure và sắp xếp các sơ đồ lớp UML của dòng Congigure. Nó sẽ rõ ràng hơn nhiều.
Nguồn cấu hình Json.
?
1
2
3
4
5
6
7
8
|
công cộng
lớp học
JsonConfigurationSource: Nguồn Cấu hình Tệp
{
công cộng
ghi đè
IConfigurationProvider Build (Trình xây dựng IConfigurationBuilder)
{
EnsureDefaults(trình xây dựng);
trở lại
mới
Nhà cung cấp cấu hình Json(
cái này
);
}
}
|
Đây là tất cả mã của JsonConfigurationSource. Nó không được sắp xếp hợp lý. Nó chỉ thực hiện một phương thức Build. Trong Build, EnsureDefaults sẽ được gọi ở đây.
?
1
2
3
4
5
6
7
8
|
công cộng
vô hiệu
EnsureDefaults(Trình xây dựng IConfigurationBuilder)
{
FileProvider = FileProvider ?? builder.GetFileProvider();
}
công cộng
tĩnh
Nhà cung cấp tệp IFile Nhà cung cấp tệp(
cái này
Trình xây dựng IConfigurationBuilder)
{
trở lại
mới
Nhà cung cấp tệp vật lý (AppContext.BaseDirectory ??
sợi dây
.Trống);
}
|
Bạn có thể thấy rằng FileProvider này theo mặc định là PhysicalFileProvider. Tại sao tôi lại dành nhiều thời gian để nhấn mạnh đến FileProvider này vì tôi rất được ưa chuộng.
JsonConfigurationProvider và FileConfigurationProvider.
Trong phương thức xây dựng của JsonConfigurationSource, một phiên bản JsonConfigurationProvider được trả về, vì vậy trực giác của tôi cho tôi biết rằng phải có điều gì đó phức tạp:confused: trong hàm tạo của nó.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
công cộng
lớp học
JsonConfigurationProvider: Nhà cung cấp FileConfiguration
{
công cộng
JsonConfigurationProvider(nguồn JsonConfigurationSource):
căn cứ
(nguồn) { }
công cộng
ghi đè
vô hiệu
Tải(Luồng luồng)
{
thử
{
Dữ liệu = JsonConfigurationFileParser.Parse(stream);
}
nắm lấy
(JsonReaderException là gì)
{
ném
mới
FormatException(Resources.Error_JSONParseError, e);
}
}
}
|
Nếu bạn không thể thấy bất cứ điều gì trong mã, chắc chắn có gì đó không ổn~~.
Hãy nhìn vào hàm tạo của cơ sở... .
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
công cộng
FileConfigurationProvider(nguồn FileConfigurationSource)
{
Nguồn = nguồn;
nếu như
(Nguồn.ReloadOnChange && Nguồn.FileProvider !=
vô giá trị
)
{
_changeTokenRegistration = ChangeToken.OnChange(
() => Nguồn.FileProvider.Watch(Nguồn.Đường dẫn),
() => {
Thread.Sleep(Nguồn.ReloadDelay);
Tải(tải lại:
ĐÚNG VẬY
);
});
}
}
|
Thật là một thiên tài. Vấn đề nằm ở hàm tạo này. Hàm tạo của nó gọi một phương thức ChangeToken.OnChange. Đây là chìa khóa để triển khai ReloadOnChange. Nếu bạn nhấp vào đây và vẫn chưa đóng nó, xin chúc mừng, cuộc vui đã bắt đầu.
Tải lại khi thay đổi 。
Nói thì rẻ. Cho tôi xem mã (đừng nói nhảm nữa và cho tôi xem mã).
?
1
2
3
4
5
6
7
|
công cộng
tĩnh
lớp học
Thay đổiToken
{
công cộng
tĩnh
ChangeTokenRegistration OnChange(Func changeTokenProducer, Hành động changeTokenConsumer)
{
trở lại
mới
ChangeTokenRegistration(changeTokenProducer, gọi lại => gọi lại(), changeTokenConsumer);
}
}
|
Trong phương thức OnChange, bất kể chức năng và hành động là gì, chỉ cần nhìn vào tên của hai tham số này, nhà sản xuất, người tiêu dùng, nhà sản xuất, người tiêu dùng Tôi không biết mình nghĩ gì khi nhìn thấy từ khóa này. khi tôi còn học tiểu học. :snake: và :rat: khi học về chuỗi thức ăn.
Vì vậy, chúng ta hãy xem :snake: ở đây là gì, :rat: là gì và chúng ta phải quay lại hàm tạo của FileConfigurationProvider.
Bạn có thể thấy nhà sản xuất:rat:yes
?
1
|
() => Nguồn.FileProvider.Watch(Nguồn.Đường dẫn)
|
người tiêu dùng:rắn:có
?
1
2
3
4
|
() => {
Thread.Sleep(Nguồn.ReloadDelay);
Tải(tải lại:
ĐÚNG VẬY
);
}
|
Hãy thử nghĩ xem, một khi con chuột thoát ra ngoài, nó sẽ bị rắn ăn thịt ngay lập tức.
Điều tương tự cũng xảy ra với chúng ta ở đây. Khi FileProvider.Watch trả về thứ gì đó, sự kiện Load() sẽ xảy ra để tải lại dữ liệu.
:snake: và :rat: rất dễ hiểu, nhưng code thì không dễ hiểu lắm. Chúng ta biết qua tham số đầu tiên Func phương thức ChangeTokenProducer của OnChange rằng :rat: đây thực chất là IChangeToken.
Đó là ChangeToken.
?
1
2
3
4
5
6
7
8
|
công cộng
giao diện
Đó là một ChangeToken
{
bool
Đã thay đổi {
lấy
; }
bool
Cuộc gọi lại ActiveChange {
lấy
; }
IDisposable RegisterChangeCallback(Hành động<
sự vật
> gọi lại,
sự vật
tình trạng);
}
|
Điểm mấu chốt của IChangeToken là có một phương thức RegisterChangeCallback trong đó. Điều :snake: eat :rat: xảy ra trong phương thức gọi lại này.
Chúng ta hãy làm một thí nghiệm về :snake: ăn :rat:.
Thí nghiệm 1.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
tĩnh
vô hiệu
Chủ yếu()
{
trong đó phyFileProvider =
mới
Nhà cung cấp tệp vật lý(
"C:\\Users\\liuzh\\MyBox\\TestSpace"
);
var ChangeToken = phyFileProvider.Watch(
"*.*"
);
changeToken.RegisterChangeCallback(_=> { Console.WriteLine(
"Con chuột đã bị rắn ăn thịt"
); },
mới
sự vật
());
Thêm Tệp Vào Đường Dẫn();
Console.ReadKey();
}
tĩnh
vô hiệu
ThêmFileToPath()
{
Console.WriteLine(
"Con chuột đã ra khỏi hang"
);
File.Create(
"C:\\Users\\liuzh\\MyBox\\TestSpace\\Con chuột đã thoát ra khỏi Hole.txt"
).Vứt bỏ();
}
|
Đây là kết quả đang chạy.

Như bạn có thể thấy, khi một tệp được tạo trong thư mục nghe, chức năng gọi lại thực thi sẽ được kích hoạt ngay lập tức, nhưng nếu chúng ta tiếp tục thay đổi (sao chép) các tệp trong thư mục nghe theo cách thủ công, chức năng gọi lại sẽ không được thực thi nữa.
Điều này là do sau khi ChangeToken giám sát các thay đổi của tệp và kích hoạt chức năng gọi lại, nhiệm vụ của ChangeToken đã hoàn thành. Nếu chúng tôi muốn tiếp tục theo dõi thì chúng tôi sẽ lấy lại mã thông báo trong chức năng gọi lại và đăng ký chức năng gọi lại của mã thông báo mới. Một sự kiện phổ biến, để bạn có thể tiếp tục theo dõi nó.
Đây là những gì ChangeToken.Onchange thực hiện. Hãy xem mã nguồn.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
công cộng
tĩnh
lớp học
Thay đổiToken
{
công cộng
tĩnh
ChangeTokenRegistration OnChange(Func changeTokenProducer, Hành động changeTokenConsumer)
{
trở lại
mới
ChangeTokenRegistration(changeTokenProducer, gọi lại => gọi lại(), changeTokenConsumer);
}
}
công cộng
lớp học
ChangeTokenRegistration
{
riêng tư
chỉ đọc
Func _changeTokenProducer;
riêng tư
chỉ đọc
Hành động _changeTokenConsumer;
riêng tư
chỉ đọc
Trạng thái _Hành động;
công cộng
ChangeTokenRegistration(Func changeTokenProducer, Action changeTokenConsumer, Trạng thái TAction)
{
_changeTokenProducer = changeTokenProducer;
_changeTokenConsumer = changeTokenConsumer;
_state = trạng thái;
var token = ChangeTokenProducer();
RegisterChangeTokenCallback(mã thông báo);
}
riêng tư
vô hiệu
RegisterChangeTokenCallback(mã thông báo IChangeToken)
{
token.RegisterChangeCallback(_ => OnChangeTokenFired(),
cái này
);
}
riêng tư
vô hiệu
OnChangeTokenBắn()
{
var token = _changeTokenProducer();
thử
{
_changeTokenConsumer(_state);
}
Cuối cùng
{
RegisterChangeTokenCallback(mã thông báo);
}
}
}
|
Nói một cách đơn giản, đó là đăng ký hàm gọi lại OnChangeTokenFired cho mã thông báo. Hãy xem xét kỹ hơn những gì được thực hiện trong OnChangeTokenFired Nói chung, có ba bước.
1. Nhận mã thông báo mới 2. Gọi cho người tiêu dùng để tiêu thụ 3. Đăng ký lại chức năng gọi lại OnChangeTokenFired cho mã thông báo mới nhận được.
Thế là nó cứ lặp đi lặp lại ~~.
Thí nghiệm 2.
Bây giờ chúng ta đã biết cách OnChange hoạt động, hãy sửa đổi mã của Thử nghiệm 1. .
?
1
2
3
4
5
6
7
|
tĩnh
vô hiệu
Chủ yếu()
{
trong đó phyFileProvider =
mới
Nhà cung cấp tệp vật lý(
"C:\\Users\\liuzh\\MyBox\\TestSpace"
);
ChangeToken.OnChange(() => phyFileProvider.Watch(
"*.*"
),
() => { Console.WriteLine(
"Con chuột đã bị rắn ăn thịt"
); });
Console.ReadKey();
}
|
Hãy xem hiệu quả thực hiện.

Có thể thấy, chỉ cần có sự thay đổi file trong thư mục được giám sát, cho dù đó là file mới hay nội dung của file bị sửa đổi thì chức năng callback trên thực tế sẽ được kích hoạt. Load(), chịu trách nhiệm tải lại dữ liệu Nhưng đó là lý do tại sao nếu ReloadOnchang được đặt thành true trong lõi Asp.net, khi cấu hình Json được cập nhật, cấu hình sẽ tự động được tải lại.
Người theo dõi tệp vật lý.
Vậy tại sao hàm gọi lại ChangeToken lại kích hoạt khi tệp thay đổi? Trên thực tế, PhysicalFileProvider gọi PhysicalFilesWatcher để giám sát hệ thống tệp. Quan sát hàm tạo của PhysicalFilesWatcher, bạn có thể thấy rằng PhysicalFilesWatcher cần truyền vào FileSystemWatcher và FileSystemWatcher là system.io. Trong lớp IO cơ bản, hãy đăng ký các sự kiện EventHandler để tạo, thay đổi, đổi tên và xóa của Watcher này trong hàm tạo. Cuối cùng, hàm gọi lại của ChangToken sẽ được gọi trong các EventHandler này, vì vậy hàm gọi lại sẽ được kích hoạt sau khi hệ thống tệp. thay đổi.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
công cộng
Người theo dõi tệp vật lý
sợi dây
root,FileSystemWatcher fileSystemWatcher,
bool
bộ lọc pollForChanges,ExclusionFilters)
{
cái này
._root = gốc;
cái này
._fileWatcher = Trình theo dõi hệ thống file;
cái này
._fileWatcher.IncludeSubdirectories =
ĐÚNG VẬY
;
cái này
._fileWatcher.Đã tạo +=
mới
Trình xử lý sự kiện hệ thống tập tin(
cái này
.Đã thay đổi);
cái này
._fileWatcher.Đã thay đổi +=
mới
Trình xử lý sự kiện hệ thống tập tin(
cái này
.Đã thay đổi);
cái này
._fileWatcher.Đã đổi tên +=
mới
Đã đổi tênEventHandler(
cái này
.OnĐã đổi tên);
cái này
._fileWatcher.Đã xóa +=
mới
Trình xử lý sự kiện hệ thống tập tin(
cái này
.Đã thay đổi);
cái này
._fileWatcher.Lỗi +=
mới
Trình xử lý sự kiện lỗi(
cái này
.OnError);
cái này
.PollForChanges = thăm dò ý kiến thay đổi;
cái này
._filters = bộ lọc;
cái này
.PollingChangeTokens =
mới
ConcurrentDictionary();
cái này
._timerFactory = (Func) (() => NonCapturingTimer.Create(
mới
TimerCallback(PhysicalFilesWatcher.RaiseChangeEvents), (
sự vật
)
cái này
.PollingChangeTokens, TimeSpan.Zero, PhysicalFilesWatcher.DefaultPollingInterval));
}
|
Nếu bạn giống tôi và quan tâm đến mã nguồn, bạn có thể tải xuống mã nguồn từ aspnet/Extensions chính thức để nghiên cứu: https://github.com/aspnet/Extensions.
Trong bài viết tiếp theo, tôi sẽ giải thích cách tùy chỉnh một configureSoure với Mysql làm nguồn dữ liệu và triển khai chức năng cập nhật tự động. Tôi cũng sẽ tổ chức sơ đồ lớp UML của các lớp liên quan. Nếu quan tâm, bạn có thể theo dõi tôi để nhận. Chuyển sang bài viết tiếp theo càng sớm càng tốt.
Địa chỉ mã liên quan đến bài viết này: https://github.com/liuzhenyulive/MiniConfiguration.
Trên đây là toàn bộ nội dung bài viết này hi vọng nó sẽ giúp ích cho việc học của mọi người và cũng mong mọi người ủng hộ mình.
Liên kết gốc: http://www.cnblogs.com/CoderAyu/p/10776845.html.
Cuối cùng, bài viết này về phân tích ngắn gọn về cập nhật tự động cấu hình Json trong .Net Core kết thúc tại đây. Nếu bạn muốn biết thêm về phân tích ngắn gọn về cập nhật tự động cấu hình Json trong .Net Core, vui lòng tìm kiếm bài viết CFSDN hoặc. tiếp tục duyệt các bài viết liên quan, tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!