|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Concurrent;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures;
/// <summary>
/// Provides <see cref="ModelExpression"/> for expressions.
/// </summary>
public class ModelExpressionProvider : IModelExpressionProvider
{
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly ConcurrentDictionary<LambdaExpression, string> _expressionTextCache;
/// <summary>
/// Creates a new <see cref="ModelExpressionProvider"/>.
/// </summary>
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
public ModelExpressionProvider(IModelMetadataProvider modelMetadataProvider)
{
ArgumentNullException.ThrowIfNull(modelMetadataProvider);
_modelMetadataProvider = modelMetadataProvider;
_expressionTextCache = new ConcurrentDictionary<LambdaExpression, string>(LambdaExpressionComparer.Instance);
}
/// <summary>
/// Gets the name for <paramref name="expression"/>.
/// </summary>
/// <typeparam name="TModel">The model type.</typeparam>
/// <typeparam name="TValue">The type of the <paramref name="expression"/> result.</typeparam>
/// <param name="expression">The expression.</param>
/// <returns>The expression name.</returns>
public string GetExpressionText<TModel, TValue>(Expression<Func<TModel, TValue>> expression)
{
ArgumentNullException.ThrowIfNull(expression);
return ExpressionHelper.GetExpressionText(expression, _expressionTextCache);
}
/// <inheritdoc />
public ModelExpression CreateModelExpression<TModel, TValue>(
ViewDataDictionary<TModel> viewData,
Expression<Func<TModel, TValue>> expression)
{
ArgumentNullException.ThrowIfNull(viewData);
ArgumentNullException.ThrowIfNull(expression);
var name = GetExpressionText(expression);
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, viewData, _modelMetadataProvider);
if (modelExplorer == null)
{
throw new InvalidOperationException(
Resources.FormatCreateModelExpression_NullModelMetadata(nameof(IModelMetadataProvider), name));
}
return new ModelExpression(name, modelExplorer);
}
/// <summary>
/// Returns a <see cref="ModelExpression"/> instance describing the given <paramref name="expression"/>.
/// </summary>
/// <typeparam name="TModel">The type of the <paramref name="viewData"/>'s <see cref="ViewDataDictionary{T}.Model"/>.</typeparam>
/// <param name="viewData">The <see cref="ViewDataDictionary{TModel}"/> containing the <see cref="ViewDataDictionary{T}.Model"/>
/// against which <paramref name="expression"/> is evaluated. </param>
/// <param name="expression">Expression name, relative to <c>viewData.Model</c>.</param>
/// <returns>A new <see cref="ModelExpression"/> instance describing the given <paramref name="expression"/>.</returns>
public ModelExpression CreateModelExpression<TModel>(
ViewDataDictionary<TModel> viewData,
string expression)
{
ArgumentNullException.ThrowIfNull(viewData);
ArgumentNullException.ThrowIfNull(expression);
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, viewData, _modelMetadataProvider);
if (modelExplorer == null)
{
throw new InvalidOperationException(
Resources.FormatCreateModelExpression_NullModelMetadata(nameof(IModelMetadataProvider), expression));
}
return new ModelExpression(expression, modelExplorer);
}
}
|