Browse Source

Added application service convention for AspNet Core.

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
d1907e342e
  1. 275
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs
  2. 6
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  3. 32
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs
  4. 34
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs
  5. 27
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs
  6. 35
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs
  7. 16
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs
  8. 12
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/IAbpControllerAssemblySettingBuilder.cs
  9. 52
      src/Volo.Abp/System/Reflection/AbpMemberInfoExtensions.cs
  10. 2
      src/Volo.Abp/Volo/Abp/Application/Services/ApplicationService.cs
  11. 2
      src/Volo.Abp/Volo/Abp/Application/Services/AsyncCrudAppService.cs
  12. 2
      src/Volo.Abp/Volo/Abp/Application/Services/CrudAppService.cs
  13. 3
      src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs
  14. 3
      src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs
  15. 3
      src/Volo.Abp/Volo/Abp/Application/Services/ICrudAppService.cs
  16. 44
      src/Volo.Abp/Volo/Abp/Http/HttpVerbHelper.cs
  17. 82
      src/Volo.Abp/Volo/Abp/Http/RemoteServiceAttribute.cs
  18. 21
      src/Volo.Abp/Volo/Abp/Reflection/ReflectionHelper.cs
  19. 67
      src/Volo.Abp/Volo/Abp/Reflection/TypeHelper.cs
  20. 2
      test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPersonAppService.cs
  21. 4
      test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PersonAppService.cs

275
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs

@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.Http;
using Volo.Abp.Reflection;
namespace Volo.Abp.AspNetCore.Mvc
{
public class AbpAppServiceConvention : IApplicationModelConvention
{
private readonly Lazy<AbpAspNetCoreMvcOptions> _configuration;
public AbpAppServiceConvention(IServiceCollection services)
{
_configuration = new Lazy<AbpAspNetCoreMvcOptions>(() =>
{
return services
.GetSingletonInstance<IAbpApplication>()
.ServiceProvider
.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>()
.Value;
}, true);
}
public void Apply(ApplicationModel application)
{
foreach (var controller in application.Controllers)
{
var type = controller.ControllerType.AsType();
var configuration = GetControllerSettingOrNull(type);
if (typeof(IApplicationService).GetTypeInfo().IsAssignableFrom(type))
{
controller.ControllerName = controller.ControllerName.RemovePostFix(ApplicationService.CommonPostfixes);
configuration?.ControllerModelConfigurer(controller);
ConfigureArea(controller, configuration);
ConfigureRemoteService(controller, configuration);
}
else
{
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(type.GetTypeInfo());
if (remoteServiceAtt != null && remoteServiceAtt.IsEnabledFor(type))
{
ConfigureRemoteService(controller, configuration);
}
}
}
}
private void ConfigureArea(ControllerModel controller, [CanBeNull] AbpControllerAssemblySetting configuration)
{
if (configuration == null)
{
return;
}
if (controller.RouteValues.ContainsKey("area"))
{
return;
}
controller.RouteValues["area"] = configuration.ModuleName;
}
private void ConfigureRemoteService(ControllerModel controller, [CanBeNull] AbpControllerAssemblySetting configuration)
{
ConfigureApiExplorer(controller);
ConfigureSelector(controller, configuration);
ConfigureParameters(controller);
}
private void ConfigureParameters(ControllerModel controller)
{
foreach (var action in controller.Actions)
{
foreach (var prm in action.Parameters)
{
if (prm.BindingInfo != null)
{
continue;
}
if (!TypeHelper.IsPrimitiveExtendedIncludingNullable(prm.ParameterInfo.ParameterType))
{
if (CanUseFormBodyBinding(action, prm))
{
prm.BindingInfo = BindingInfo.GetBindingInfo(new[] { new FromBodyAttribute() });
}
}
}
}
}
private bool CanUseFormBodyBinding(ActionModel action, ParameterModel parameter)
{
if (_configuration.Value.FormBodyBindingIgnoredTypes.Any(t => t.IsAssignableFrom(parameter.ParameterInfo.ParameterType)))
{
return false;
}
foreach (var selector in action.Selectors)
{
if (selector.ActionConstraints == null)
{
continue;
}
foreach (var actionConstraint in selector.ActionConstraints)
{
var httpMethodActionConstraint = actionConstraint as HttpMethodActionConstraint;
if (httpMethodActionConstraint == null)
{
continue;
}
if (httpMethodActionConstraint.HttpMethods.All(hm => hm.IsIn("GET", "DELETE", "TRACE", "HEAD")))
{
return false;
}
}
}
return true;
}
private void ConfigureApiExplorer(ControllerModel controller)
{
if (controller.ApiExplorer.GroupName.IsNullOrEmpty())
{
controller.ApiExplorer.GroupName = controller.ControllerName;
}
if (controller.ApiExplorer.IsVisible == null)
{
var controllerType = controller.ControllerType.AsType();
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(controllerType.GetTypeInfo());
if (remoteServiceAtt != null)
{
controller.ApiExplorer.IsVisible =
remoteServiceAtt.IsEnabledFor(controllerType) &&
remoteServiceAtt.IsMetadataEnabledFor(controllerType);
}
else
{
controller.ApiExplorer.IsVisible = true;
}
}
foreach (var action in controller.Actions)
{
ConfigureApiExplorer(action);
}
}
private void ConfigureApiExplorer(ActionModel action)
{
if (action.ApiExplorer.IsVisible == null)
{
var remoteServiceAtt = ReflectionHelper.GetSingleAttributeOrDefault<RemoteServiceAttribute>(action.ActionMethod);
if (remoteServiceAtt != null)
{
action.ApiExplorer.IsVisible =
remoteServiceAtt.IsEnabledFor(action.ActionMethod) &&
remoteServiceAtt.IsMetadataEnabledFor(action.ActionMethod);
}
}
}
private void ConfigureSelector(ControllerModel controller, [CanBeNull] AbpControllerAssemblySetting configuration)
{
RemoveEmptySelectors(controller.Selectors);
if (controller.Selectors.Any(selector => selector.AttributeRouteModel != null))
{
return;
}
var moduleName = GetModuleNameOrDefault(controller.ControllerType.AsType());
foreach (var action in controller.Actions)
{
ConfigureSelector(moduleName, controller.ControllerName, action, configuration);
}
}
private void ConfigureSelector(string moduleName, string controllerName, ActionModel action, [CanBeNull] AbpControllerAssemblySetting configuration)
{
RemoveEmptySelectors(action.Selectors);
if (!action.Selectors.Any())
{
AddAbpServiceSelector(moduleName, controllerName, action, configuration);
}
else
{
NormalizeSelectorRoutes(moduleName, controllerName, action);
}
}
private void AddAbpServiceSelector(string moduleName, string controllerName, ActionModel action, [CanBeNull] AbpControllerAssemblySetting configuration)
{
var abpServiceSelectorModel = new SelectorModel
{
AttributeRouteModel = CreateAbpServiceAttributeRouteModel(moduleName, controllerName, action)
};
var verb = configuration?.UseConventionalHttpVerbs == true
? HttpVerbHelper.GetConventionalVerbForMethodName(action.ActionName)
: HttpVerbHelper.DefaultHttpVerb;
abpServiceSelectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { verb }));
action.Selectors.Add(abpServiceSelectorModel);
}
private static void NormalizeSelectorRoutes(string moduleName, string controllerName, ActionModel action)
{
foreach (var selector in action.Selectors)
{
if (selector.AttributeRouteModel == null)
{
selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(
moduleName,
controllerName,
action
);
}
}
}
private string GetModuleNameOrDefault(Type controllerType)
{
return GetControllerSettingOrNull(controllerType)?.ModuleName ??
AbpControllerAssemblySetting.DefaultServiceModuleName;
}
[CanBeNull]
private AbpControllerAssemblySetting GetControllerSettingOrNull(Type controllerType)
{
return _configuration.Value.ControllerAssemblySettings.GetSettingOrNull(controllerType);
}
private static AttributeRouteModel CreateAbpServiceAttributeRouteModel(string moduleName, string controllerName, ActionModel action)
{
return new AttributeRouteModel(
new RouteAttribute(
$"api/services/{moduleName}/{controllerName}/{action.ActionName}"
)
);
}
private static void RemoveEmptySelectors(IList<SelectorModel> selectors)
{
selectors
.Where(IsEmptySelector)
.ToList()
.ForEach(s => selectors.Remove(s));
}
private static bool IsEmptySelector(SelectorModel selector)
{
return selector.AttributeRouteModel == null && selector.ActionConstraints.IsNullOrEmpty();
}
}
}

6
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -8,6 +8,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.EmbeddedFiles;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
using Microsoft.AspNetCore.Mvc;
namespace Volo.Abp.AspNetCore.Mvc
{
@ -34,6 +35,11 @@ namespace Volo.Abp.AspNetCore.Mvc
)
)
);
services.Configure<MvcOptions>(mvcOptions =>
{
mvcOptions.AddAbp(services);
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)

32
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Volo.Abp.AspNetCore.Mvc
{
public class AbpAspNetCoreMvcOptions
{
//TODO: Group into a class since they are related.
public ControllerAssemblySettingList ControllerAssemblySettings { get; }
public List<Type> FormBodyBindingIgnoredTypes { get; }
public AbpAspNetCoreMvcOptions()
{
FormBodyBindingIgnoredTypes = new List<Type>
{
typeof(IFormFile)
};
}
public AbpControllerAssemblySettingBuilder CreateControllersForAppServices(
Assembly assembly,
string moduleName = AbpControllerAssemblySetting.DefaultServiceModuleName,
bool useConventionalHttpVerbs = true)
{
var setting = new AbpControllerAssemblySetting(moduleName, assembly, useConventionalHttpVerbs);
ControllerAssemblySettings.Add(setting);
return new AbpControllerAssemblySettingBuilder(setting);
}
}
}

34
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs

@ -0,0 +1,34 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace Volo.Abp.AspNetCore.Mvc
{
public class AbpControllerAssemblySetting
{
/// <summary>
/// "app".
/// </summary>
public const string DefaultServiceModuleName = "app";
public string ModuleName { get; }
public Assembly Assembly { get; }
public bool UseConventionalHttpVerbs { get; }
public Func<Type, bool> TypePredicate { get; set; }
public Action<ControllerModel> ControllerModelConfigurer { get; set; }
public AbpControllerAssemblySetting(string moduleName, Assembly assembly, bool useConventionalHttpVerbs)
{
ModuleName = moduleName;
Assembly = assembly;
UseConventionalHttpVerbs = useConventionalHttpVerbs;
TypePredicate = type => true;
ControllerModelConfigurer = controller => { };
}
}
}

27
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs

@ -0,0 +1,27 @@
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace Volo.Abp.AspNetCore.Mvc
{
public class AbpControllerAssemblySettingBuilder : IAbpControllerAssemblySettingBuilder
{
private readonly AbpControllerAssemblySetting _setting;
public AbpControllerAssemblySettingBuilder(AbpControllerAssemblySetting setting)
{
_setting = setting;
}
public AbpControllerAssemblySettingBuilder Where(Func<Type, bool> predicate)
{
_setting.TypePredicate = predicate;
return this;
}
public AbpControllerAssemblySettingBuilder ConfigureControllerModel(Action<ControllerModel> configurer)
{
_setting.ControllerModelConfigurer = configurer;
return this;
}
}
}

35
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs

@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc
{
internal static class AbpMvcOptionsExtensions
{
public static void AddAbp(this MvcOptions options, IServiceCollection services)
{
AddConventions(options, services);
AddFilters(options);
AddModelBinders(options);
}
private static void AddConventions(MvcOptions options, IServiceCollection services)
{
options.Conventions.Add(new AbpAppServiceConvention(services));
}
private static void AddFilters(MvcOptions options)
{
//options.Filters.AddService(typeof(AbpAuthorizationFilter));
//options.Filters.AddService(typeof(AbpAuditActionFilter));
//options.Filters.AddService(typeof(AbpValidationActionFilter));
//options.Filters.AddService(typeof(AbpUowActionFilter));
//options.Filters.AddService(typeof(AbpExceptionFilter));
//options.Filters.AddService(typeof(AbpResultFilter));
}
private static void AddModelBinders(MvcOptions options)
{
//options.ModelBinderProviders.Add(new AbpDateTimeModelBinderProvider());
}
}
}

16
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ControllerAssemblySettingList.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.Mvc
{
public class ControllerAssemblySettingList : List<AbpControllerAssemblySetting>
{
[CanBeNull]
public AbpControllerAssemblySetting GetSettingOrNull(Type controllerType)
{
return this.FirstOrDefault(controllerSetting => controllerSetting.Assembly == controllerType.GetAssembly());
}
}
}

12
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/IAbpControllerAssemblySettingBuilder.cs

@ -0,0 +1,12 @@
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace Volo.Abp.AspNetCore.Mvc
{
public interface IAbpControllerAssemblySettingBuilder
{
AbpControllerAssemblySettingBuilder Where(Func<Type, bool> predicate);
AbpControllerAssemblySettingBuilder ConfigureControllerModel(Action<ControllerModel> configurer);
}
}

52
src/Volo.Abp/System/Reflection/AbpMemberInfoExtensions.cs

@ -0,0 +1,52 @@
using System.Linq;
namespace System.Reflection
{
/// <summary>
/// Extensions to <see cref="MemberInfo"/>.
/// </summary>
public static class AbpMemberInfoExtensions
{
/// <summary>
/// Gets a single attribute for a member.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">The member that will be checked for the attribute</param>
/// <param name="inherit">Include inherited attributes</param>
/// <returns>Returns the attribute object if found. Returns null if not found.</returns>
public static TAttribute GetSingleAttributeOrNull<TAttribute>(this MemberInfo memberInfo, bool inherit = true)
where TAttribute : Attribute
{
if (memberInfo == null)
{
throw new ArgumentNullException(nameof(memberInfo));
}
var attrs = memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).ToArray();
if (attrs.Length > 0)
{
return (TAttribute)attrs[0];
}
return default(TAttribute);
}
public static TAttribute GetSingleAttributeOfTypeOrBaseTypesOrNull<TAttribute>(this Type type, bool inherit = true)
where TAttribute : Attribute
{
var attr = type.GetTypeInfo().GetSingleAttributeOrNull<TAttribute>();
if (attr != null)
{
return attr;
}
if (type.GetTypeInfo().BaseType == null)
{
return null;
}
return type.GetTypeInfo().BaseType.GetSingleAttributeOfTypeOrBaseTypesOrNull<TAttribute>(inherit);
}
}
}

2
src/Volo.Abp/Volo/Abp/Application/Services/ApplicationService.cs

@ -2,6 +2,8 @@ namespace Volo.Abp.Application.Services
{
public abstract class ApplicationService : AbpServiceBase, IApplicationService
{
public static string[] CommonPostfixes = { "AppService", "ApplicationService", "Service" };
/* Will be added when implemented
- AbpSession
- ...

2
src/Volo.Abp/Volo/Abp/Application/Services/AsyncCrudAppService.cs

@ -6,7 +6,7 @@ using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
namespace Abp.Application.Services
namespace Volo.Abp.Application.Services
{
public abstract class AsyncCrudAppService<TEntity, TEntityDto>
: AsyncCrudAppService<TEntity, TEntityDto, Guid>

2
src/Volo.Abp/Volo/Abp/Application/Services/CrudAppService.cs

@ -4,7 +4,7 @@ using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace Abp.Application.Services
namespace Volo.Abp.Application.Services
{
public abstract class CrudAppService<TEntity, TEntityDto>
: CrudAppService<TEntity, TEntityDto, Guid>

3
src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs

@ -2,11 +2,10 @@
using System.Linq;
using System.Linq.Dynamic.Core;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace Abp.Application.Services
namespace Volo.Abp.Application.Services
{
/// <summary>
/// This is a common base class for CrudAppService and AsyncCrudAppService classes.

3
src/Volo.Abp/Volo/Abp/Application/Services/IAsyncCrudAppService.cs

@ -1,9 +1,8 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Abp.Application.Services
namespace Volo.Abp.Application.Services
{
public interface IAsyncCrudAppService<TEntityDto>
: IAsyncCrudAppService<TEntityDto, Guid>

3
src/Volo.Abp/Volo/Abp/Application/Services/ICrudAppService.cs

@ -1,8 +1,7 @@
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Abp.Application.Services
namespace Volo.Abp.Application.Services
{
public interface ICrudAppService<TEntityDto>
: ICrudAppService<TEntityDto, Guid>

44
src/Volo.Abp/Volo/Abp/Http/HttpVerbHelper.cs

@ -0,0 +1,44 @@
using System;
namespace Volo.Abp.Http
{
public class HttpVerbHelper //TODO: Internal?
{
public const string DefaultHttpVerb = "POST";
public static string GetConventionalVerbForMethodName(string methodName)
{
if (methodName.StartsWith("Get", StringComparison.OrdinalIgnoreCase))
{
return "GET";
}
if (methodName.StartsWith("Put", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Update", StringComparison.OrdinalIgnoreCase))
{
return "PUT";
}
if (methodName.StartsWith("Delete", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Remove", StringComparison.OrdinalIgnoreCase))
{
return "DELETE";
}
if (methodName.StartsWith("Patch", StringComparison.OrdinalIgnoreCase))
{
return "PATCH";
}
if (methodName.StartsWith("Post", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Create", StringComparison.OrdinalIgnoreCase) ||
methodName.StartsWith("Insert", StringComparison.OrdinalIgnoreCase))
{
return "POST";
}
//Default
return DefaultHttpVerb;
}
}
}

82
src/Volo.Abp/Volo/Abp/Http/RemoteServiceAttribute.cs

@ -0,0 +1,82 @@
using System;
using System.Reflection;
namespace Volo.Abp.Http
{
[Serializable]
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Method)]
public class RemoteServiceAttribute : Attribute
{
/// <summary>
/// Default: true.
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// Default: true.
/// </summary>
public bool IsMetadataEnabled { get; set; }
public RemoteServiceAttribute(bool isEnabled = true)
{
IsEnabled = isEnabled;
IsMetadataEnabled = true;
}
public virtual bool IsEnabledFor(Type type)
{
return IsEnabled;
}
public virtual bool IsEnabledFor(MethodInfo method)
{
return IsEnabled;
}
public virtual bool IsMetadataEnabledFor(Type type)
{
return IsMetadataEnabled;
}
public virtual bool IsMetadataEnabledFor(MethodInfo method)
{
return IsMetadataEnabled;
}
public static bool IsExplicitlyEnabledFor(Type type)
{
var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && remoteServiceAttr.IsEnabledFor(type);
}
public static bool IsExplicitlyDisabledFor(Type type)
{
var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(type);
}
public static bool IsMetadataExplicitlyEnabledFor(Type type)
{
var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && remoteServiceAttr.IsMetadataEnabledFor(type);
}
public static bool IsMetadataExplicitlyDisabledFor(Type type)
{
var remoteServiceAttr = type.GetTypeInfo().GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && !remoteServiceAttr.IsMetadataEnabledFor(type);
}
public static bool IsMetadataExplicitlyDisabledFor(MethodInfo method)
{
var remoteServiceAttr = method.GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && !remoteServiceAttr.IsMetadataEnabledFor(method);
}
public static bool IsMetadataExplicitlyEnabledFor(MethodInfo method)
{
var remoteServiceAttr = method.GetSingleAttributeOrNull<RemoteServiceAttribute>();
return remoteServiceAttr != null && remoteServiceAttr.IsMetadataEnabledFor(method);
}
}
}

21
src/Volo.Abp/Volo/Abp/Reflection/ReflectionHelper.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Volo.Abp.Reflection
@ -70,5 +71,25 @@ namespace Volo.Abp.Reflection
AddImplementedGenericTypes(result, givenTypeInfo.BaseType, genericType);
}
/// <summary>
/// Tries to gets an of attribute defined for a class member and it's declaring type including inherited attributes.
/// Returns default value if it's not declared at all.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="defaultValue">Default value (null as default)</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static TAttribute GetSingleAttributeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
where TAttribute : Attribute
{
//Get attribute on the member
if (memberInfo.IsDefined(typeof(TAttribute), inherit))
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().First();
}
return defaultValue;
}
}
}

67
src/Volo.Abp/Volo/Abp/Reflection/TypeHelper.cs

@ -0,0 +1,67 @@
using System;
using System.Reflection;
namespace Volo.Abp.Reflection
{
/// <summary>
/// Some simple type-checking methods used internally.
/// </summary>
public static class TypeHelper
{
public static bool IsFunc(object obj)
{
if (obj == null)
{
return false;
}
var type = obj.GetType();
if (!type.GetTypeInfo().IsGenericType)
{
return false;
}
return type.GetGenericTypeDefinition() == typeof(Func<>);
}
public static bool IsFunc<TReturn>(object obj)
{
return obj != null && obj.GetType() == typeof(Func<TReturn>);
}
public static bool IsPrimitiveExtendedIncludingNullable(Type type, bool includeEnums = false)
{
if (IsPrimitiveExtended(type, includeEnums))
{
return true;
}
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return IsPrimitiveExtended(type.GenericTypeArguments[0], includeEnums);
}
return false;
}
private static bool IsPrimitiveExtended(Type type, bool includeEnums)
{
if (type.GetTypeInfo().IsPrimitive)
{
return true;
}
if (includeEnums && type.GetTypeInfo().IsEnum)
{
return true;
}
return type == typeof (string) ||
type == typeof (decimal) ||
type == typeof (DateTime) ||
type == typeof (DateTimeOffset) ||
type == typeof (TimeSpan) ||
type == typeof (Guid);
}
}
}

2
test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPersonAppService.cs

@ -1,4 +1,4 @@
using Abp.Application.Services;
using Volo.Abp.Application.Services;
namespace Volo.Abp.TestApp.Application
{

4
test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PersonAppService.cs

@ -1,6 +1,6 @@
using Abp.Application.Services;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.TestApp.Domain;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Application.Services;
namespace Volo.Abp.TestApp.Application
{

Loading…
Cancel
Save