Introducing Activator for ViewComponents.
This commit is contained in:
parent
75525ab525
commit
e6f4f0fec6
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
|
|
||||||
|
|
@ -261,12 +261,14 @@
|
||||||
<Compile Include="ViewComponents\DefaultViewComponentInvoker.cs" />
|
<Compile Include="ViewComponents\DefaultViewComponentInvoker.cs" />
|
||||||
<Compile Include="ViewComponents\DefaultViewComponentInvokerFactory.cs" />
|
<Compile Include="ViewComponents\DefaultViewComponentInvokerFactory.cs" />
|
||||||
<Compile Include="ViewComponents\DefaultViewComponentInvokerProvider.cs" />
|
<Compile Include="ViewComponents\DefaultViewComponentInvokerProvider.cs" />
|
||||||
|
<Compile Include="ViewComponents\DefaultViewComponentActivator.cs" />
|
||||||
<Compile Include="ViewComponents\DefaultViewComponentSelector.cs" />
|
<Compile Include="ViewComponents\DefaultViewComponentSelector.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentHelper.cs" />
|
<Compile Include="ViewComponents\IViewComponentHelper.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentInvoker.cs" />
|
<Compile Include="ViewComponents\IViewComponentInvoker.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentInvokerFactory.cs" />
|
<Compile Include="ViewComponents\IViewComponentInvokerFactory.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentInvokerProvider.cs" />
|
<Compile Include="ViewComponents\IViewComponentInvokerProvider.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentResult.cs" />
|
<Compile Include="ViewComponents\IViewComponentResult.cs" />
|
||||||
|
<Compile Include="ViewComponents\IViewComponentActivator.cs" />
|
||||||
<Compile Include="ViewComponents\IViewComponentSelector.cs" />
|
<Compile Include="ViewComponents\IViewComponentSelector.cs" />
|
||||||
<Compile Include="ViewComponents\JsonViewComponentResult.cs" />
|
<Compile Include="ViewComponents\JsonViewComponentResult.cs" />
|
||||||
<Compile Include="ViewComponents\ViewComponent.cs" />
|
<Compile Include="ViewComponents\ViewComponent.cs" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the <see cref="IViewComponentActivator"/> that is registered by default.
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultViewComponentActivator : IViewComponentActivator
|
||||||
|
{
|
||||||
|
private readonly Func<Type, PropertyActivator<ViewContext>[]> _getPropertiesToActivate;
|
||||||
|
private readonly IReadOnlyDictionary<Type, Func<ViewContext, object>> _valueAccessorLookup;
|
||||||
|
private readonly ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]> _injectActions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="DefaultViewComponentActivator"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DefaultViewComponentActivator()
|
||||||
|
{
|
||||||
|
_valueAccessorLookup = CreateValueAccessorLookup();
|
||||||
|
_injectActions = new ConcurrentDictionary<Type, PropertyActivator<ViewContext>[]>();
|
||||||
|
_getPropertiesToActivate = type =>
|
||||||
|
PropertyActivator<ViewContext>.GetPropertiesToActivate(
|
||||||
|
type, typeof(ActivateAttribute), CreateActivateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Activate([NotNull] object viewComponent, [NotNull] ViewContext context)
|
||||||
|
{
|
||||||
|
var propertiesToActivate = _injectActions.GetOrAdd(viewComponent.GetType(),
|
||||||
|
_getPropertiesToActivate);
|
||||||
|
|
||||||
|
for (var i = 0; i < propertiesToActivate.Length; i++)
|
||||||
|
{
|
||||||
|
var activateInfo = propertiesToActivate[i];
|
||||||
|
activateInfo.Activate(viewComponent, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a lookup dictionary for the values to be activated.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a readonly dictionary of the values corresponding to the types.</returns>
|
||||||
|
protected virtual IReadOnlyDictionary<Type, Func<ViewContext, object>> CreateValueAccessorLookup()
|
||||||
|
{
|
||||||
|
return new Dictionary<Type, Func<ViewContext, object>>
|
||||||
|
{
|
||||||
|
{ typeof(ViewContext), (context) => context },
|
||||||
|
{
|
||||||
|
typeof(ViewDataDictionary),
|
||||||
|
(context) =>
|
||||||
|
{
|
||||||
|
return new ViewDataDictionary(context.ViewData)
|
||||||
|
{
|
||||||
|
Model = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyActivator<ViewContext> CreateActivateInfo(PropertyInfo property)
|
||||||
|
{
|
||||||
|
Func<ViewContext, object> valueAccessor;
|
||||||
|
if (!_valueAccessorLookup.TryGetValue(property.PropertyType, out valueAccessor))
|
||||||
|
{
|
||||||
|
valueAccessor = (viewContext) =>
|
||||||
|
{
|
||||||
|
var serviceProvider = viewContext.HttpContext.RequestServices;
|
||||||
|
var service = serviceProvider.GetService(property.PropertyType);
|
||||||
|
if (typeof(ICanHasViewContext).IsAssignableFrom(property.PropertyType))
|
||||||
|
{
|
||||||
|
((ICanHasViewContext)service).Contextualize(viewContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return service;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PropertyActivator<ViewContext>(property, valueAccessor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,15 +15,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly TypeInfo _componentType;
|
private readonly TypeInfo _componentType;
|
||||||
|
private readonly IViewComponentActivator _viewComponentActivator;
|
||||||
private readonly object[] _args;
|
private readonly object[] _args;
|
||||||
|
|
||||||
public DefaultViewComponentInvoker(
|
public DefaultViewComponentInvoker(
|
||||||
[NotNull] IServiceProvider serviceProvider,
|
[NotNull] IServiceProvider serviceProvider,
|
||||||
|
[NotNull] IViewComponentActivator viewComponentActivator,
|
||||||
[NotNull] TypeInfo componentType,
|
[NotNull] TypeInfo componentType,
|
||||||
object[] args)
|
object[] args)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_componentType = componentType;
|
_componentType = componentType;
|
||||||
|
_viewComponentActivator = viewComponentActivator;
|
||||||
_args = args ?? new object[0];
|
_args = args ?? new object[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,16 +76,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var activator = _serviceProvider.GetService<ITypeActivator>();
|
var activator = _serviceProvider.GetService<ITypeActivator>();
|
||||||
var component = activator.CreateInstance(_serviceProvider, _componentType.AsType());
|
var component = activator.CreateInstance(_serviceProvider, _componentType.AsType());
|
||||||
|
_viewComponentActivator.Activate(component, context);
|
||||||
Injector.InjectProperty(component, "ViewContext", context);
|
|
||||||
|
|
||||||
// We're flowing the viewbag across, but the concept of model doesn't really apply here
|
|
||||||
var viewData = new ViewDataDictionary(context.ViewData);
|
|
||||||
viewData.Model = null;
|
|
||||||
Injector.InjectProperty(component, "ViewData", viewData);
|
|
||||||
|
|
||||||
Injector.CallInitializer(component, _serviceProvider);
|
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,20 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DefaultViewComponentInvokerProvider : IViewComponentInvokerProvider
|
public class DefaultViewComponentInvokerProvider : IViewComponentInvokerProvider
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly IViewComponentActivator _viewComponentActivator;
|
||||||
|
|
||||||
public DefaultViewComponentInvokerProvider(IServiceProvider serviceProvider)
|
public DefaultViewComponentInvokerProvider(IServiceProvider serviceProvider,
|
||||||
|
IViewComponentActivator viewComponentActivator)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
|
_viewComponentActivator = viewComponentActivator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
@ -22,7 +26,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public void Invoke([NotNull] ViewComponentInvokerProviderContext context, [NotNull] Action callNext)
|
public void Invoke([NotNull] ViewComponentInvokerProviderContext context, [NotNull] Action callNext)
|
||||||
{
|
{
|
||||||
context.Result =
|
context.Result =
|
||||||
new DefaultViewComponentInvoker(_serviceProvider, context.ComponentType, context.Arguments);
|
new DefaultViewComponentInvoker(
|
||||||
|
_serviceProvider, _viewComponentActivator, context.ComponentType, context.Arguments);
|
||||||
callNext();
|
callNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to activate an instantiated ViewComponent
|
||||||
|
/// </summary>
|
||||||
|
public interface IViewComponentActivator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// When implemented in a type, activates an instantiated ViewComponent.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="viewComponent">The ViewComponent to activate.</param>
|
||||||
|
/// <param name="context">The <see cref="ViewContext"/> for the executing <see cref="ViewComponent"/>.</param>
|
||||||
|
void Activate(object viewComponent, ViewContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public abstract class ViewComponent
|
public abstract class ViewComponent
|
||||||
{
|
{
|
||||||
private dynamic _viewBag;
|
private dynamic _viewBag;
|
||||||
private ICompositeViewEngine _viewEngine;
|
|
||||||
|
|
||||||
public HttpContext Context
|
public HttpContext Context
|
||||||
{
|
{
|
||||||
|
|
@ -30,20 +29,20 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Activate]
|
||||||
public ViewContext ViewContext { get; set; }
|
public ViewContext ViewContext { get; set; }
|
||||||
|
|
||||||
|
[Activate]
|
||||||
public ViewDataDictionary ViewData { get; set; }
|
public ViewDataDictionary ViewData { get; set; }
|
||||||
|
|
||||||
|
[Activate]
|
||||||
|
public ICompositeViewEngine ViewEngine { get; set; }
|
||||||
|
|
||||||
public ContentViewComponentResult Content([NotNull] string content)
|
public ContentViewComponentResult Content([NotNull] string content)
|
||||||
{
|
{
|
||||||
return new ContentViewComponentResult(content);
|
return new ContentViewComponentResult(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(ICompositeViewEngine viewEngine)
|
|
||||||
{
|
|
||||||
_viewEngine = viewEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonViewComponentResult Json([NotNull] object value)
|
public JsonViewComponentResult Json([NotNull] object value)
|
||||||
{
|
{
|
||||||
return new JsonViewComponentResult(value);
|
return new JsonViewComponentResult(value);
|
||||||
|
|
@ -72,7 +71,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
viewData.Model = model;
|
viewData.Model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ViewViewComponentResult(_viewEngine, viewName, viewData);
|
return new ViewViewComponentResult(ViewEngine, viewName, viewData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
yield return describe.Scoped<IUrlHelper, UrlHelper>();
|
yield return describe.Scoped<IUrlHelper, UrlHelper>();
|
||||||
|
|
||||||
yield return describe.Transient<IViewComponentSelector, DefaultViewComponentSelector>();
|
yield return describe.Transient<IViewComponentSelector, DefaultViewComponentSelector>();
|
||||||
|
yield return describe.Singleton<IViewComponentActivator, DefaultViewComponentActivator>();
|
||||||
yield return describe.Transient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
yield return describe.Transient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||||
yield return describe.Transient<INestedProvider<ViewComponentInvokerProviderContext>,
|
yield return describe.Transient<INestedProvider<ViewComponentInvokerProviderContext>,
|
||||||
DefaultViewComponentInvokerProvider>();
|
DefaultViewComponentInvokerProvider>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
#if NET45
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNet.PipelineCore;
|
||||||
|
using Microsoft.AspNet.Routing;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultViewComponentActivatorTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void DefaultViewComponentActivatorSetsAllPropertiesMarkedAsActivate()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var activator = new DefaultViewComponentActivator();
|
||||||
|
var instance = new TestViewComponent();
|
||||||
|
var helper = Mock.Of<IHtmlHelper<object>>();
|
||||||
|
var serviceProvider = new Mock<IServiceProvider>();
|
||||||
|
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||||
|
var viewContext = GetViewContext(serviceProvider.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
activator.Activate(instance, viewContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(helper, instance.Html);
|
||||||
|
Assert.Same(viewContext, instance.ViewContext);
|
||||||
|
Assert.IsType<ViewDataDictionary>(instance.ViewData);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DefaultViewComponentActivatorSetsModelAsNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var activator = new DefaultViewComponentActivator();
|
||||||
|
var helper = Mock.Of<IHtmlHelper<object>>();
|
||||||
|
var serviceProvider = new Mock<IServiceProvider>();
|
||||||
|
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||||
|
var viewContext = GetViewContext(serviceProvider.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
activator.Activate(new TestViewComponent(), viewContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Null(viewContext.ViewData.Model);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DefaultViewComponentActivatorActivatesNonBuiltInTypes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var activator = new DefaultViewComponentActivator();
|
||||||
|
var helper = Mock.Of<IHtmlHelper<object>>();
|
||||||
|
var myTestService = new MyService();
|
||||||
|
var serviceProvider = new Mock<IServiceProvider>();
|
||||||
|
serviceProvider.Setup(p => p.GetService(typeof(IHtmlHelper<object>))).Returns(helper);
|
||||||
|
serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService);
|
||||||
|
var viewContext = GetViewContext(serviceProvider.Object);
|
||||||
|
var instance = new TestViewComponentWithCustomDataType();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
activator.Activate(instance, viewContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(myTestService, instance.TestMyServiceObject);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DefaulViewComponentActivatorContextualizesService()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var activator = new DefaultViewComponentActivator();
|
||||||
|
var instance = new TestClassUsingMyService();
|
||||||
|
var myTestService = new MyService();
|
||||||
|
var serviceProvider = new Mock<IServiceProvider>();
|
||||||
|
serviceProvider.Setup(p => p.GetService(typeof(MyService))).Returns(myTestService);
|
||||||
|
var viewContext = GetViewContext(serviceProvider.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
activator.Activate(instance, viewContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(myTestService, instance.MyTestService);
|
||||||
|
Assert.Same(viewContext, instance.MyTestService.ViewContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ViewContext GetViewContext(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var httpContext = new Mock<DefaultHttpContext>();
|
||||||
|
httpContext.SetupGet(c => c.RequestServices)
|
||||||
|
.Returns(serviceProvider);
|
||||||
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
|
var actionContext = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
|
return new ViewContext(actionContext,
|
||||||
|
Mock.Of<IView>(),
|
||||||
|
new ViewDataDictionary(Mock.Of<IModelMetadataProvider>()),
|
||||||
|
TextWriter.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestViewComponent : ViewComponent
|
||||||
|
{
|
||||||
|
[Activate]
|
||||||
|
public IHtmlHelper<object> Html { get; private set; }
|
||||||
|
|
||||||
|
public Task ExecuteAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestViewComponentWithCustomDataType : TestViewComponent
|
||||||
|
{
|
||||||
|
[Activate]
|
||||||
|
public MyService TestMyServiceObject { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyService : ICanHasViewContext
|
||||||
|
{
|
||||||
|
public ViewContext ViewContext { get; private set; }
|
||||||
|
|
||||||
|
public void Contextualize(ViewContext viewContext)
|
||||||
|
{
|
||||||
|
ViewContext = viewContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestClassUsingMyService
|
||||||
|
{
|
||||||
|
[Activate]
|
||||||
|
public MyService MyTestService { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
<Compile Include="Filters\ProducesAttributeTests.cs" />
|
<Compile Include="Filters\ProducesAttributeTests.cs" />
|
||||||
<Compile Include="Formatters\OutputFormatterTests.cs" />
|
<Compile Include="Formatters\OutputFormatterTests.cs" />
|
||||||
<Compile Include="Formatters\TextPlainFormatterTests.cs" />
|
<Compile Include="Formatters\TextPlainFormatterTests.cs" />
|
||||||
|
<Compile Include="DefaultViewComponentActivatorTests.cs" />
|
||||||
<Compile Include="Logging\BeginScopeContext.cs" />
|
<Compile Include="Logging\BeginScopeContext.cs" />
|
||||||
<Compile Include="Logging\TestLoggerFactory.cs" />
|
<Compile Include="Logging\TestLoggerFactory.cs" />
|
||||||
<Compile Include="Logging\WriteCoreContext.cs" />
|
<Compile Include="Logging\WriteCoreContext.cs" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue