Hearth.ArcGIS
2.0.0
dotnet add package Hearth.ArcGIS --version 2.0.0
NuGet\Install-Package Hearth.ArcGIS -Version 2.0.0
<PackageReference Include="Hearth.ArcGIS" Version="2.0.0" />
<PackageVersion Include="Hearth.ArcGIS" Version="2.0.0" />
<PackageReference Include="Hearth.ArcGIS" />
paket add Hearth.ArcGIS --version 2.0.0
#r "nuget: Hearth.ArcGIS, 2.0.0"
#:package Hearth.ArcGIS@2.0.0
#addin nuget:?package=Hearth.ArcGIS&version=2.0.0
#tool nuget:?package=Hearth.ArcGIS&version=2.0.0
Hearth ArcGIS Framework Extensions (DryIoC, Options, NLog, AutoMapper...)
1 Using IoC and DI
1.1 Service Registration
1.1.1 Marking Services
Method 1: Using Attributes
Mark service types with the [Service]
attribute:
public interface IHelloService
{
void SayHello();
}
[Service]
public class HelloService : IHelloService
{
public void SayHello()
{
Console.WriteLine("Hello, World!");
}
}
ServiceAttribute
definition:
/// <summary>
/// Service marker attribute
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class ServiceAttribute : Attribute
{
/// <summary>
/// Service registration key
/// </summary>
public string? ServiceKey { get; set; }
/// <summary>
/// Service registration type
/// </summary>
public Type? ServiceType { get; set; }
/// <summary>
/// Service reuse mode
/// </summary>
public ReuseEnum Reuse { get; set; }
/// <summary>
/// Service attribute
/// </summary>
/// <param name="serviceType"> Service registration type </param>
/// <param name="serviceKey"> Service registration key </param>
/// <param name="reuse"> Service reuse mode </param>
public ServiceAttribute(Type? serviceType = null, string? serviceKey = null, ReuseEnum reuse = ReuseEnum.Default)
{
ServiceType = serviceType;
ServiceKey = serviceKey;
Reuse = reuse;
}
}
ReuseEnum
options:
/// <summary>
/// Reuse mode enumeration
/// </summary>
public enum ReuseEnum
{
/// <summary>
/// Default.
/// </summary>
Default,
/// <summary>
/// Same as scoped but requires <see cref="ThreadScopeContext"/>.
/// </summary>
InThread,
/// <summary>
/// Scoped to any scope (named or unnamed).
/// </summary>
Scoped,
/// <summary>
/// Same as <see cref="Scoped"/>, but falls back to <see cref="Singleton"/> when no scope is available.
/// </summary>
ScopedOrSingleton,
/// <summary>
/// Singleton in container.
/// </summary>
Singleton,
/// <summary>
/// Transient (not reused).
/// </summary>
Transient,
}
Method 2: Implement Service Interfaces
Implement ITransientService
, ISingletonService
, IScopedService
, IScopedOrSingletonService
, or IInThreadService
:
public class HelloService : IHelloService, ITransientService
{
public void SayHello()
{
Console.WriteLine("Hello, World!");
}
}
1.1.2 Registering Services
Register services during module initialization using HearthApp.Container.RegisterAssemblyAndRefrencedAssembliesTypes(Assembly assembly)
:
internal class Module1 : Module
{
private static Module1 _this = null;
public static Module1 Current => _this ??= (Module1)FrameworkApplication.FindModule("Hearth_ArcGIS_Samples_Module");
public Module1()
{
HearthApp.App.RegisterAssemblyAndRefrencedAssembliesTypes(this.GetType().Assembly);
}
}
1.2 Dependency Injection
1.2.1 Property Injection
// IInjectable - Default injection
// IScopeInjectable - Scoped injection
// INamedScopeInjectable - Named scope injection
internal class SampleButton1 : Button, IInjectable
{
[Inject]
private readonly IHelloService? _helloService;
public SampleButton1()
{
this.InjectServices();
// Alternative without [Inject]:
// this.InjectPropertiesAndFields();
}
protected override void OnClick()
{
_helloService?.SayHello();
}
}
1.2.1.1 InjectAttribute
/// <summary>
/// Auto-injection attribute
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class InjectAttribute : Attribute
{
/// <summary>
/// Service registration key
/// </summary>
public object? Key { get; set; }
/// <summary>
/// Service type
/// </summary>
public Type? ServiceType { get; set; }
/// <summary>
/// Injection service attribute
/// </summary>
/// <param name="key"> Service registration key </param>
/// <param name="serviceType"> Service type </param>
public InjectAttribute(object? key = null, Type? serviceType = null)
{
Key = key;
ServiceType = serviceType;
}
}
1.2.2 Constructor Injection
1.2.2.1 Default Injection
Service registration:
public interface IHelloService
{
void SayHello();
}
[Service]
public class HelloHearthAService : IHelloService
{
public void SayHello()
{
Console.WriteLine("Hello, Hearth A!");
}
}
Constructor injection:
public class HelloTest
{
private readonly IHelloService _service;
public HelloTest(IHelloService service)
{
_service = service;
}
}
1.2.2.2 Key-based Injection
Service registration:
[Service(typeof(IHelloService), "A", ReuseEnum.Transient)]
public class HelloHearthAService : IHelloService
{
public void SayHello() => Console.WriteLine("Hello, Hearth A!");
}
[Service(typeof(IHelloService), "B", ReuseEnum.Transient)]
public class HelloHearthBService : IHelloService
{
public void SayHello() => Console.WriteLine("Hello, Hearth B!");
}
Constructor injection:
public class HelloTest
{
private readonly IHelloService _aService;
private readonly IHelloService _bService;
public HelloTest(
[InjectParam("A")] IHelloService aService,
[InjectParam("B")] IHelloService bService)
{
_aService = aService;
_bService = bService;
}
}
1.2.3 ViewModel Locator
Use ViewModelLocator
in XAML to bind view models. ViewModels can be registered using [Service]
or auto-registered.
ViewModel:
using ArcGIS.Desktop.Framework.Contracts;
namespace Hearth.ArcGIS.Samples.Dialogs
{
public class SampleWindow1ViewModel : ViewModelBase
{
private string _sampleText = "Sample Text";
public string SampleText
{
get => _sampleText;
set => SetProperty(ref _sampleText, value, () => SampleText);
}
}
}
XAML usage:
<Window ...
xmlns:ha="clr-namespace:Hearth.ArcGIS;assembly=Hearth.ArcGIS"
ha:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<TextBlock Text="{Binding SampleText}" />
</Grid>
</Window>
1.3 Custom Container Initialization
Customize container initialization by implementing ContainerBuilderBase
and HearthAppBase
:
using DryIoc;
public class CustomContainerBuilder : ContainerBuilder
{
public override Container Build()
{
Container container = new Container(
rules => rules
.With(
FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic,
null,
PropertiesAndFields.All()));
AddNlog(container);
AddAutoMapper(container);
AddViewModelLocationProvider(container);
return container;
}
}
public class CustomHearthApp : HearthAppBase
{
private static CustomHearthApp? _instance;
public static CustomHearthApp Instance => _instance ??= new CustomHearthApp(new CustomContainerBuilder());
public CustomHearthApp(IContainerBuilder containerBuilder) : base(containerBuilder)
{
}
}
Initialize before DI usage:
CustomHearthApp.Instance.Container.RegisterAssemblyAndRefrencedAssembliesTypes(this.GetType().Assembly);
2 Using Options Configuration
Reference: Options Documentation
2.1 Create Configuration Class
namespace Hearth.ArcGIS.Samples.Configs
{
public class SampleSettings
{
public string Value1 { get; set; }
public int Value2 { get; set; }
public double Value3 { get; set; }
public string[] Value4 { get; set; }
}
}
2.2 Register Configuration During Module Initialization
internal class Module1 : Module
{
public Module1()
{
// samplesettings.json content:
// "SampleSettings": {
// "Value1": "asd",
// "Value2": 123,
// "Value3": 123.456,
// "Value4": [ "asd", "zxc", "qwe" ]
// }
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("samplesettings.json", true, true)
.Build();
HearthApp.App.Configure<SampleSettings>(
configuration.GetSection(typeof(SampleSettings).Name));
HearthApp.App.RegisterAssemblyAndRefrencedAssembliesTypes(this.GetType().Assembly);
}
}
2.3 Implement IConfigurationProvider<T>
for Auto-Configuration
// Automatically registered on initialization
public class SampleSettingsConfigurationProvider : IConfigurationProvider<SampleSettings>
{
public IConfiguration GetConfiguration()
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("samplesettings.json", true, true)
.Build();
return configuration.GetSection(typeof(SampleSettings).Name);
}
}
3 Using NLog Logging
Reference: NLog Tutorial, Advanced NLog Configuration, NLog Configuration Options
3.1 Log Configuration
Configuration file location: ...\Pro\bin\nlog.config
Example configuration:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="OFF" internalLogFile="c:\\temp\\nlog-internal.log">
<variable name="logDirectory" value="${basedir}/GeoApp/logs"/>
<targets>
<target xsi:type="File" name="f_all"
fileName="${logDirectory}/${shortdate}.log"
archiveNumbering="Sequence"
archiveEvery="Day"
maxArchiveDays="30"
archiveAboveSize="104857600"
layout="[${longdate}] ${threadid} ${level} ${callsite} ${callsite-linenumber} ${message} ${exception}" />
</targets>
<rules>
<logger name="Hearth.*" minlevel="Debug" writeTo="f_all" />
<logger name="*" minlevel="Warn" writeTo="f_all" />
</rules>
</nlog>
3.2 Logger Usage
[Service]
public class TestLogService
{
private readonly ILogger<TestLogService> _logger;
public TestLogService(ILogger<TestLogService> logger)
{
_logger = logger;
}
public void WriteLog()
{
_logger?.LogTrace("Configured Type Logger Class LogTrace");
_logger?.LogDebug("Configured Type Logger Class LogDebug");
_logger?.LogInformation("Configured Type Logger Class LogInformation");
_logger?.LogWarning("Configured Type Logger Class LogWarning");
_logger?.LogError("Configured Type Logger Class LogError");
_logger?.LogCritical("Configured Type Logger Class LogCritical");
}
}
Log output:
[2025-02-19 15:34:02.0141] 1 Trace Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 16 Configured Type Logger Class LogTrace
[2025-02-19 15:34:02.0141] 1 Debug Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 17 Configured Type Logger Class LogDebug
[2025-02-19 15:34:02.0141] 1 Info Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 18 Configured Type Logger Class LogInformation
[2025-02-19 15:34:02.0141] 1 Warn Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 19 Configured Type Logger Class LogWarning
[2025-02-19 15:34:02.0141] 1 Error Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 20 Configured Type Logger Class LogError
[2025-02-19 15:34:02.0141] 1 Fatal Hearth.ArcGIS.Samples.Services.TestLogService.WriteLog 21 Configured Type Logger Class LogCritical
4 Using AutoMapper
Reference: AutoMapper Documentation
4.1 Model
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public DateTime Birthday { get; set; }
}
public class PersonVO : ViewModelBase
{
private Guid _id;
public Guid Id { get => _id; set => SetProperty(ref _id, value); }
private string _name;
public string Name { get => _name; set => SetProperty(ref _name, value); }
private int _age;
public int Age { get => _age; set => SetProperty(ref _age, value); }
private DateTime _birthday;
public DateTime Birthday { get => _birthday; set => SetProperty(ref _birthday, value); }
}
4.2 Configuration
Method 1: Using Profile Configuration
using AutoMapper;
namespace Hearth.ArcGIS.Samples
{
public class PersonProfile : Profile
{
public PersonProfile()
{
CreateMap<Person, PersonVO>().ReverseMap();
}
}
}
Method 2: Using [AutoMap] Attribute
[AutoMap(typeof(PersonVO))]
public class Person { /* ... */ }
[AutoMap(typeof(Person))]
public class PersonVO : ViewModelBase { /* ... */ }
4.3 Usage
public class SomeSample
{
private readonly IMapper _mapper;
public SomeSample(IMapper mapper)
{
_mapper = mapper;
}
public void DoSomeThings(PersonVO personVO)
{
Person person = _mapper.Map<Person>(personVO);
// ...
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0-windows7.0 is compatible. net7.0-windows was computed. net8.0-windows was computed. net8.0-windows7.0 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net6.0-windows7.0
- AutoMapper (>= 13.0.1)
- DryIoc.dll (>= 5.4.3)
- DryIoc.Microsoft.DependencyInjection (>= 6.1.1)
- Microsoft.Extensions.Configuration (>= 2.0.0)
- Microsoft.Extensions.Configuration.Json (>= 2.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Options (>= 6.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 2.0.0)
- NLog (>= 5.4.0)
- NLog.Extensions.Logging (>= 5.4.0)
-
net8.0-windows7.0
- AutoMapper (>= 14.0.0)
- DryIoc.dll (>= 5.4.3)
- DryIoc.Microsoft.DependencyInjection (>= 6.2.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Configuration.Json (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
- Microsoft.Extensions.Options (>= 8.0.2)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- NLog (>= 5.4.0)
- NLog.Extensions.Logging (>= 5.4.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Hearth.ArcGIS:
Package | Downloads |
---|---|
Hearth.ArcGIS.Infrastructure
Hearth ArcGIS 框架基础设施扩展 |
GitHub repositories
This package is not used by any popular GitHub repositories.
添加构造函数注入参数选项