File: Forms\Mapping\EditContextFormMappingExtensions.cs
Web Access
Project: src\src\Components\Web\src\Microsoft.AspNetCore.Components.Web.csproj (Microsoft.AspNetCore.Components.Web)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
 
namespace Microsoft.AspNetCore.Components.Forms.Mapping;
 
internal static class EditContextFormMappingExtensions
{
    private static readonly object _key = new();
 
    public static IDisposable EnableFormMappingContextExtensions(this EditContext context, FormMappingContext mappingContext)
    {
        ArgumentNullException.ThrowIfNull(context, nameof(context));
        ArgumentNullException.ThrowIfNull(mappingContext, nameof(mappingContext));
 
        context.Properties[_key] = mappingContext;
 
        return new MappingContextEventSubscriptions(context, mappingContext);
    }
 
    public static string? GetAttemptedValue(this EditContext context, string fieldName)
    {
        ArgumentNullException.ThrowIfNull(context, nameof(context));
        ArgumentNullException.ThrowIfNull(fieldName, nameof(fieldName));
 
        if (context.Properties.TryGetValue(_key, out var result) && result is FormMappingContext mappingContext)
        {
            return mappingContext.GetAttemptedValue(fieldName);
        }
 
        return null;
    }
 
    private sealed class MappingContextEventSubscriptions : IDisposable
    {
        private readonly EditContext _editContext;
        private readonly FormMappingContext _mappingContext;
        private ValidationMessageStore? _messages;
        private bool _hasmessages;
 
        public MappingContextEventSubscriptions(EditContext editContext, FormMappingContext mappingContext)
        {
            _editContext = editContext;
            _mappingContext = mappingContext;
 
            _editContext.OnValidationRequested += OnValidationRequested;
        }
 
        private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e)
        {
            if (_messages != null)
            {
                // We already added the messages from the mapping context,
                // we don't have to do anything.
                return;
            }
 
            _messages = new ValidationMessageStore(_editContext);
            var adddedMessages = false;
            foreach (var error in _mappingContext.GetAllErrors())
            {
                var owner = error.Container;
                var key = error.Name;
                var errors = error.ErrorMessages;
                FieldIdentifier fieldIdentifier;
                fieldIdentifier = new FieldIdentifier(owner ?? _editContext.Model, key);
 
                foreach (var errorMessage in errors)
                {
                    adddedMessages = true;
                    // TODO: We need to support localizing the error message.
                    _messages.Add(fieldIdentifier, errorMessage.ToString(CultureInfo.CurrentCulture));
                    _hasmessages = true;
                }
            }
 
            if (adddedMessages)
            {
                // There were mapping errors, notify.
                _editContext.NotifyValidationStateChanged();
            }
        }
 
        public void Dispose()
        {
            _messages?.Clear();
            _editContext.OnValidationRequested -= OnValidationRequested;
            if (_hasmessages)
            {
                _editContext.NotifyValidationStateChanged();
            }
        }
    }
}