diff --git a/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationCodeProcessor.cs b/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationCodeProcessor.cs
index 5e2584ac..5c53f4be 100644
--- a/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationCodeProcessor.cs
+++ b/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationCodeProcessor.cs
@@ -14,7 +14,8 @@ namespace OpenRiaServices.Server.Authentication
///
/// implementation that sets the base class of both the
/// context and entity types generated by a provider implementing
- /// .
+ /// . or
+ /// .
///
internal sealed class AuthenticationCodeProcessor : CodeProcessor
{
@@ -263,19 +264,19 @@ internal static CodeCommentStatementCollection GetDocComments(string resourceCom
}
///
- /// Validates that the authentication service implements the interface
+ /// Validates that the authentication service implements or interface
/// naturally for use in codegen.
///
///
/// This check ensures no part of the interface was implemented explicitly.
///
/// The domain service description for the type that implemented
- /// the interface.
+ /// the or interface.
///
- /// The generic version of implemented
+ /// The generic version of or implemented
/// by the service type of the .
///
- /// is thrown if the interface
+ /// is thrown if the or interface
/// is not correctly implemented.
///
private static void CheckIAuthentication(DomainServiceDescription authenticationServiceDescription, out Type genericIAuthenticationType)
@@ -285,7 +286,7 @@ private static void CheckIAuthentication(DomainServiceDescription authentication
bool implementsGetUser = false;
bool implementsUpdateUser = false;
- if (!typeof(IAuthentication<>).DefinitionIsAssignableFrom(authenticationServiceDescription.DomainServiceType, out genericIAuthenticationType))
+ if (!authenticationServiceDescription.TryGetAuthenticationServiceType(out genericIAuthenticationType))
{
throw new InvalidOperationException(Resources.ApplicationServices_MustBeIAuth);
}
@@ -296,16 +297,16 @@ private static void CheckIAuthentication(DomainServiceDescription authentication
{
switch (doe.Name)
{
- case "Login":
+ case string name when name.StartsWith("Login", StringComparison.OrdinalIgnoreCase):
implementsLogin = CheckIAuthenticationLogin(doe, userType);
break;
- case "Logout":
+ case string name when name.StartsWith("Logout", StringComparison.OrdinalIgnoreCase):
implementsLogout = CheckIAuthenticationLogout(doe, userType);
break;
- case "GetUser":
+ case string name when name.StartsWith("GetUser", StringComparison.OrdinalIgnoreCase):
implementsGetUser = CheckIAuthenticationGetUser(doe, userType);
break;
- case "UpdateUser":
+ case string name when name.StartsWith("UpdateUser", StringComparison.OrdinalIgnoreCase):
implementsUpdateUser = CheckIAuthenticationUpdateUser(doe, userType);
break;
default:
@@ -323,10 +324,10 @@ private static void CheckIAuthentication(DomainServiceDescription authentication
}
///
- /// Validates that the operation entry represents for use in codegen.
+ /// Validates that the operation entry represents or for use in codegen.
///
/// The entry to validate
- /// The user type. T in .
+ /// The user type. T in or .
/// Whether the operation entry represents Login
private static bool CheckIAuthenticationLogin(DomainOperationEntry doe, Type userType)
{
@@ -355,10 +356,10 @@ private static bool CheckIAuthenticationLogin(DomainOperationEntry doe, Type use
}
///
- /// Validates that the operation entry represents for use in codegen.
+ /// Validates that the operation entry represents or for use in codegen.
///
/// The entry to validate
- /// The user type. T in .
+ /// The user type. T in or .
/// Whether the operation entry represents Logout
private static bool CheckIAuthenticationLogout(DomainOperationEntry doe, Type userType)
{
@@ -383,10 +384,10 @@ private static bool CheckIAuthenticationLogout(DomainOperationEntry doe, Type us
}
///
- /// Validates that the operation entry represents for use in codegen.
+ /// Validates that the operation entry represents or for use in codegen.
///
/// The entry to validate
- /// The user type. T in .
+ /// The user type. T in or .
/// Whether the operation entry represents GetUser
private static bool CheckIAuthenticationGetUser(DomainOperationEntry doe, Type userType)
{
@@ -411,10 +412,10 @@ private static bool CheckIAuthenticationGetUser(DomainOperationEntry doe, Type u
}
///
- /// Validates that the operation entry represents for use in codegen.
+ /// Validates that the operation entry represents or for use in codegen.
///
/// The entry to validate
- /// The user type. T in .
+ /// The user type. T in or .
/// Whether the operation entry represents UpdateUser
private static bool CheckIAuthenticationUpdateUser(DomainOperationEntry doe, Type userType)
{
diff --git a/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationServiceAttribute.cs b/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationServiceAttribute.cs
index 5583df97..81f8bac1 100644
--- a/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationServiceAttribute.cs
+++ b/src/OpenRiaServices.Server/Framework/Authentication/AuthenticationServiceAttribute.cs
@@ -7,7 +7,7 @@ namespace OpenRiaServices.Server.Authentication
///
///
/// This attribute is used to associate the with
- /// an implementation of the interface.
+ /// an implementation of the and interface.
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public sealed class AuthenticationServiceAttribute : DomainIdentifierAttribute
diff --git a/src/OpenRiaServices.Server/Framework/Authentication/IAsyncAuthentication.cs b/src/OpenRiaServices.Server/Framework/Authentication/IAsyncAuthentication.cs
new file mode 100644
index 00000000..5276e0ea
--- /dev/null
+++ b/src/OpenRiaServices.Server/Framework/Authentication/IAsyncAuthentication.cs
@@ -0,0 +1,74 @@
+using System.Threading.Tasks;
+
+namespace OpenRiaServices.Server.Authentication
+{
+ ///
+ /// An interface for a that encapsulates the authentication domain. A
+ /// domain service implementing this interface will be used to populate the user on the client.
+ ///
+ ///
+ /// OpenRiaServices.Client.Authentication.WebAuthenticationService
+ /// will work with the DomainContext generated for any domain service implementing this
+ /// interface.
+ ///
+ /// is designed as an update method, and will be invoked via
+ /// SubmitChanges on the client. This has a couple implications. First,
+ /// invoking via AuthenticationService.SaveUser will submit all
+ /// changes that have occurred in the DomainContext and may invoke other update methods.
+ /// Second, invoking other update methods on the DomainContext from the client will submit
+ /// all changes and may invoke .
+ ///
+ ///
+ /// The type of the user entity
+ [AuthenticationService]
+ public interface IAuthenticationAsync where T : IUser
+ {
+ ///
+ /// Authenticates and returns the user with the specified name and password.
+ ///
+ ///
+ /// This method will return a single user if the
+ /// authentication was successful. If the user could not be authenticated, null
+ /// will be returned.
+ ///
+ /// The userName associated with the user to authenticate
+ /// The password associated with the user to authenticate
+ /// Whether the authentication should persist between sessions
+ /// Optional implementation-specific data
+ /// A single user or null if authentication failed
+ [Query(IsComposable = false, HasSideEffects = true)]
+ Task LoginAsync(string userName, string password, bool isPersistent, string customData);
+
+ ///
+ /// Logs an authenticated user out.
+ ///
+ ///
+ /// This method will return a single, anonymous user.
+ ///
+ /// A single, default user.
+ [Query(IsComposable = false, HasSideEffects = true)]
+ Task LogoutAsync();
+
+ ///
+ /// Gets the principal and profile for the current user.
+ ///
+ ///
+ /// This method will return a single user. If the user is not
+ /// authenticated, an anonymous user will be returned.
+ ///
+ /// An enumerable with a single user.
+ [Query(IsComposable = false)]
+ Task GetUserAsync();
+
+ ///
+ /// Updates the profile for the authenticated user.
+ ///
+ /// The updated user
+ /// is thrown if the authenticated
+ /// user does not have the correct permissions to update the profile.
+ ///
+ [Update]
+ [RequiresAuthentication]
+ Task UpdateUserAsync(T user);
+ }
+}
diff --git a/src/OpenRiaServices.Server/Framework/Authentication/IUser.cs b/src/OpenRiaServices.Server/Framework/Authentication/IUser.cs
index a616cb6a..2be9f75b 100644
--- a/src/OpenRiaServices.Server/Framework/Authentication/IUser.cs
+++ b/src/OpenRiaServices.Server/Framework/Authentication/IUser.cs
@@ -6,7 +6,7 @@ namespace OpenRiaServices.Server.Authentication
/// Interface for user entities that has properties for passing principal values to the client.
///
///
- /// This class is designed for use with the interface.
+ /// This class is designed for use with the or interface.
/// It provides properties to support serialization of principal values to an entity class
/// generated from a type implementing this interface.
///
diff --git a/src/OpenRiaServices.Server/Framework/Data/DomainServiceDescription.cs b/src/OpenRiaServices.Server/Framework/Data/DomainServiceDescription.cs
index 0fd09965..6fb6b02f 100644
--- a/src/OpenRiaServices.Server/Framework/Data/DomainServiceDescription.cs
+++ b/src/OpenRiaServices.Server/Framework/Data/DomainServiceDescription.cs
@@ -10,6 +10,7 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
+using OpenRiaServices.Server.Authentication;
namespace OpenRiaServices.Server
{
@@ -2081,5 +2082,13 @@ private HashSet GetOrCreateRootEntityTypes()
}
return this._rootEntityTypes;
}
+
+ public bool IsAuthenticationService() => TryGetAuthenticationServiceType(out var _);
+
+ public bool TryGetAuthenticationServiceType(out Type genericType)
+ {
+ return typeof(IAuthentication<>).DefinitionIsAssignableFrom(DomainServiceType, out genericType)
+ || typeof(IAuthenticationAsync<>).DefinitionIsAssignableFrom(DomainServiceType, out genericType);
+ }
}
}
diff --git a/src/OpenRiaServices.Server/Test/Authentication/AuthenticationCodeProcessorTest.cs b/src/OpenRiaServices.Server/Test/Authentication/AuthenticationCodeProcessorTest.cs
index 7ecfaf2d..981592f6 100644
--- a/src/OpenRiaServices.Server/Test/Authentication/AuthenticationCodeProcessorTest.cs
+++ b/src/OpenRiaServices.Server/Test/Authentication/AuthenticationCodeProcessorTest.cs
@@ -6,6 +6,7 @@
using Microsoft.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenRiaServices.Server.Authentication;
+using System.Threading.Tasks;
namespace OpenRiaServices.Server.Test.Authentication
{
@@ -214,26 +215,26 @@ private static void Generate()
null /* unused in negative tests */);
}
- public class AcpDomainService : DomainService, IAuthentication where T : IUser
+ public class AcpDomainService : DomainService, IAuthenticationAsync where T : IUser
{
#region IAuthentication Members
- public T Login(string userName, string password, bool isPersistent, string customData)
+ public Task LoginAsync(string userName, string password, bool isPersistent, string customData)
{
throw new NotImplementedException();
}
- public T Logout()
+ public Task LogoutAsync()
{
throw new NotImplementedException();
}
- public T GetUser()
+ public Task GetUserAsync()
{
throw new NotImplementedException();
}
- public void UpdateUser(T user)
+ public Task UpdateUserAsync(T user)
{
throw new NotImplementedException();
}
diff --git a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpDomainContextGenerator.cs b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpDomainContextGenerator.cs
index 25ac9473..f8032319 100644
--- a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpDomainContextGenerator.cs
+++ b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpDomainContextGenerator.cs
@@ -66,7 +66,7 @@ private void GenerateUsings()
protected virtual void GenerateClassDeclaration()
{
string baseType = "OpenRiaServices.Client.DomainContext";
- if(typeof(IAuthentication<>).DefinitionIsAssignableFrom(this.DomainServiceDescription.DomainServiceType))
+ if(DomainServiceDescription.IsAuthenticationService())
{
baseType = @"global::OpenRiaServices.Client.Authentication.AuthenticationDomainContextBase";
}
diff --git a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.cs b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.cs
index 14f05769..46f6db7d 100644
--- a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.cs
+++ b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.cs
@@ -94,12 +94,10 @@ protected virtual void GenerateProperties()
DomainServiceDescription defaultAuthDescription = this.GetDefaultAuthDescription();
- if(defaultAuthDescription != null)
+ if(defaultAuthDescription != null
+ && defaultAuthDescription.TryGetAuthenticationServiceType(out Type genericType)
+ && (genericType.GetGenericArguments().Count() == 1))
{
- Type genericType = null;
- typeof(IAuthentication<>).DefinitionIsAssignableFrom(defaultAuthDescription.DomainServiceType, out genericType);
- if ((genericType != null) && (genericType.GetGenericArguments().Count() == 1))
- {
string typeName = CodeGenUtilities.GetTypeName(genericType.GetGenericArguments()[0]);
this.Write("public new ");
@@ -112,8 +110,6 @@ protected virtual void GenerateProperties()
this.Write(")base.User; }\r\n}\r\n");
-
- }
}
}
diff --git a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.partial.cs b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.partial.cs
index 798d4f48..eb5fe396 100644
--- a/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.partial.cs
+++ b/src/OpenRiaServices.Tools.TextTemplate/Framework/CSharpGenerators/CSharpWebContextGenerator.partial.cs
@@ -54,7 +54,7 @@ private DomainServiceDescription GetDefaultAuthDescription()
{
DomainServiceDescription defaultAuthDescription = null;
IEnumerable authDescriptions =
- this.DomainServiceDescriptions.Where(d => typeof(IAuthentication<>).DefinitionIsAssignableFrom(d.DomainServiceType));
+ this.DomainServiceDescriptions.Where(d => d.IsAuthenticationService());
if (authDescriptions.Count() > 1)
{
this.ClientCodeGenerator.CodeGenerationHost.LogMessage(
diff --git a/src/OpenRiaServices.Tools/Framework/WebContextGenerator.cs b/src/OpenRiaServices.Tools/Framework/WebContextGenerator.cs
index 764bb9b9..db452fb7 100644
--- a/src/OpenRiaServices.Tools/Framework/WebContextGenerator.cs
+++ b/src/OpenRiaServices.Tools/Framework/WebContextGenerator.cs
@@ -54,7 +54,8 @@ public override void Generate()
// Find the AuthenticationServices and if there's just one, use it as the default.
IEnumerable authDescriptions =
- this.ClientProxyGenerator.DomainServiceDescriptions.Where(d => typeof(IAuthentication<>).DefinitionIsAssignableFrom(d.DomainServiceType));
+ this.ClientProxyGenerator.DomainServiceDescriptions
+ .Where(d => d.IsAuthenticationService());
DomainServiceDescription defaultAuthDescription = null;
if (authDescriptions.Count() > 1)
{
@@ -148,29 +149,26 @@ public override void Generate()
// }
// -->
// ----------------------------------------------------------------
- if (defaultAuthDescription != null)
+ if (defaultAuthDescription != null
+ && defaultAuthDescription.TryGetAuthenticationServiceType(out Type genericType)
+ && (genericType.GetGenericArguments().Length == 1))
{
- Type genericType = null;
- typeof(IAuthentication<>).DefinitionIsAssignableFrom(defaultAuthDescription.DomainServiceType, out genericType);
- if ((genericType != null) && (genericType.GetGenericArguments().Length == 1))
- {
- CodeMemberProperty userProperty = new CodeMemberProperty();
-
- userProperty.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;
- userProperty.Type = CodeGenUtilities.GetTypeReference(
- genericType.GetGenericArguments()[0], this.ClientProxyGenerator, proxyClass);
- userProperty.Name = "User";
- userProperty.HasGet = true;
- userProperty.GetStatements.Add(
- new CodeMethodReturnStatement(
- new CodeCastExpression(userProperty.Type,
- new CodePropertyReferenceExpression(
- new CodeBaseReferenceExpression(),
- "User"))));
- userProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentUser, this.ClientProxyGenerator.IsCSharp));
-
- proxyClass.Members.Add(userProperty);
- }
+ CodeMemberProperty userProperty = new CodeMemberProperty();
+
+ userProperty.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final;
+ userProperty.Type = CodeGenUtilities.GetTypeReference(
+ genericType.GetGenericArguments()[0], this.ClientProxyGenerator, proxyClass);
+ userProperty.Name = "User";
+ userProperty.HasGet = true;
+ userProperty.GetStatements.Add(
+ new CodeMethodReturnStatement(
+ new CodeCastExpression(userProperty.Type,
+ new CodePropertyReferenceExpression(
+ new CodeBaseReferenceExpression(),
+ "User"))));
+ userProperty.Comments.AddRange(CodeGenUtilities.GetDocComments(Resource.WebContext_CommentUser, this.ClientProxyGenerator.IsCSharp));
+
+ proxyClass.Members.Add(userProperty);
}
}
#endregion