diff --git a/Source/Csla.Axml.Android/Resources/Resource.Designer.cs b/Source/Csla.Axml.Android/Resources/Resource.Designer.cs index 8dfd1b05dd..0e2429d078 100644 --- a/Source/Csla.Axml.Android/Resources/Resource.Designer.cs +++ b/Source/Csla.Axml.Android/Resources/Resource.Designer.cs @@ -40,8 +40,8 @@ private Attribute() public partial class String { - // aapt resource value: 0x7f020000 - public static int ApplicationName = 2130837504; + // aapt resource value: 0x7F010000 + public static int ApplicationName = 2130771968; static String() { diff --git a/Source/Csla.Shared/DataPortal.cs b/Source/Csla.Shared/DataPortal.cs index 2b1cd466a4..5c2c12e392 100644 --- a/Source/Csla.Shared/DataPortal.cs +++ b/Source/Csla.Shared/DataPortal.cs @@ -646,7 +646,7 @@ public static T CreateChild(params object[] parameters) public static async Task CreateChildAsync() { Server.ChildDataPortal portal = new Server.ChildDataPortal(); - return await portal.CreateAsync(); + return await portal.CreateAsync(EmptyCriteria.Instance); } /// @@ -704,7 +704,7 @@ public static T FetchChild(params object[] parameters) public static async Task FetchChildAsync() { Server.ChildDataPortal portal = new Server.ChildDataPortal(); - return await portal.FetchAsync(); + return await portal.FetchAsync(EmptyCriteria.Instance); } /// @@ -752,6 +752,35 @@ public static void UpdateChild(object child, params object[] parameters) portal.Update(child, parameters); } + /// + /// Inserts, updates or deletes an existing + /// child business object. + /// + /// + /// Business object to update. + /// + public static async Task UpdateChildAsync(object child) + { + Server.ChildDataPortal portal = new Server.ChildDataPortal(); + await portal.UpdateAsync(child).ConfigureAwait(false); + } + + /// + /// Inserts, updates or deletes an existing + /// child business object. + /// + /// + /// Business object to update. + /// + /// + /// Parameters passed to child update method. + /// + public static async Task UpdateChildAsync(object child, params object[] parameters) + { + Server.ChildDataPortal portal = new Server.ChildDataPortal(); + await portal.UpdateAsync(child, parameters).ConfigureAwait(false); + } + private static DataPortalClient.IDataPortalProxyFactory _dataProxyFactory; /// diff --git a/Source/Csla.Shared/DataPortalOperationAttributes.cs b/Source/Csla.Shared/DataPortalOperationAttributes.cs index 0cd106ac2d..3df66ba74a 100644 --- a/Source/Csla.Shared/DataPortalOperationAttributes.cs +++ b/Source/Csla.Shared/DataPortalOperationAttributes.cs @@ -14,7 +14,7 @@ namespace Csla /// via dependency injection. /// [AttributeUsage(AttributeTargets.Parameter)] - public class FromServicesAttribute : Attribute + public class InjectAttribute : Attribute { } /// @@ -124,4 +124,13 @@ public class UpdateChildAttribute : Attribute [AttributeUsage(AttributeTargets.Method)] public class DeleteSelfChildAttribute : Attribute { } + + /// + /// Specifies a method used by the server-side + /// data portal to execute a child command + /// object during an update operation. + /// + [AttributeUsage(AttributeTargets.Method)] + public class ExecuteChildAttribute : Attribute + { } } diff --git a/Source/Csla.Shared/DataPortalT.cs b/Source/Csla.Shared/DataPortalT.cs index 62c25205bd..2053f9fcd0 100644 --- a/Source/Csla.Shared/DataPortalT.cs +++ b/Source/Csla.Shared/DataPortalT.cs @@ -70,7 +70,7 @@ public DataPortalAsyncResult(T result, Csla.Core.ContextDictionary globalContext } } - private static object GetCriteriaFromArray(params object[] criteria) + internal static object GetCriteriaFromArray(params object[] criteria) { if (criteria == null) return null; @@ -82,7 +82,7 @@ private static object GetCriteriaFromArray(params object[] criteria) return new Core.MobileList(criteria); } - private static object[] GetCriteriaArray(object criteria) + internal static object[] GetCriteriaArray(object criteria) { if (criteria == EmptyCriteria) return null; diff --git a/Source/Csla.Shared/Reflection/ServiceProviderMethodCaller.cs b/Source/Csla.Shared/Reflection/ServiceProviderMethodCaller.cs index 414c414f35..bf7d0c9e72 100644 --- a/Source/Csla.Shared/Reflection/ServiceProviderMethodCaller.cs +++ b/Source/Csla.Shared/Reflection/ServiceProviderMethodCaller.cs @@ -196,7 +196,7 @@ private static ParameterInfo[] GetCriteriaParameters(System.Reflection.MethodInf var result = new List(); foreach (var item in method.GetParameters()) { - if (item.CustomAttributes.Count(a => a.AttributeType == typeof(FromServicesAttribute)) == 0) + if (item.CustomAttributes.Count(a => a.AttributeType == typeof(InjectAttribute)) == 0) result.Add(item); } return result.ToArray(); @@ -224,7 +224,7 @@ public static async Task CallMethodTryAsync(object obj, System.Reflectio foreach (var item in methodParameters) { - if (item.CustomAttributes.Where(a => a.AttributeType == typeof(FromServicesAttribute)).Count() > 0) + if (item.CustomAttributes.Where(a => a.AttributeType == typeof(InjectAttribute)).Count() > 0) { if (service != null) plist[index] = service.GetService(item.ParameterType); diff --git a/Source/Csla.Shared/Server/ChildDataPortal.cs b/Source/Csla.Shared/Server/ChildDataPortal.cs index 2a597bc812..e32e55c7a9 100644 --- a/Source/Csla.Shared/Server/ChildDataPortal.cs +++ b/Source/Csla.Shared/Server/ChildDataPortal.cs @@ -43,7 +43,7 @@ public object Create(System.Type objectType, params object[] parameters) /// public async Task CreateAsync() { - return (T) await Create(typeof(T), false, null).ConfigureAwait(false); + return (T) await Create(typeof(T), false, EmptyCriteria.Instance).ConfigureAwait(false); } /// @@ -59,11 +59,7 @@ public async Task CreateAsync(params object[] parameters) private async Task Create(System.Type objectType, bool hasParameters, params object[] parameters) { - object criteria = EmptyCriteria.Instance; - if (hasParameters && parameters == null) - criteria = null; - else if (hasParameters) - criteria = parameters; + var criteria = DataPortal.GetCriteriaFromArray(parameters); DataPortalTarget obj = null; var eventArgs = new DataPortalEventArgs(null, objectType, criteria, DataPortalOperations.Create); @@ -131,7 +127,7 @@ public object Fetch(Type objectType, params object[] parameters) /// Type of business object to retrieve. public async Task FetchAsync() { - return (T)await Fetch(typeof(T), false, null).ConfigureAwait(false); + return (T)await Fetch(typeof(T), false, EmptyCriteria.Instance).ConfigureAwait(false); } /// @@ -148,11 +144,7 @@ public async Task FetchAsync(params object[] parameters) private async Task Fetch(Type objectType, bool hasParameters, params object[] parameters) { - object criteria = EmptyCriteria.Instance; - if (hasParameters && parameters == null) - criteria = null; - else if (hasParameters) - criteria = parameters; + var criteria = DataPortal.GetCriteriaFromArray(parameters); DataPortalTarget obj = null; var eventArgs = new DataPortalEventArgs(null, objectType, parameters, DataPortalOperations.Fetch); @@ -197,7 +189,7 @@ private async Task Fetch(Type objectType, bool hasParameters, params obj /// Business object to update. public void Update(object obj) { - Update(obj, false, false, null); + Update(obj, false, false, null).Wait(); } /// @@ -209,7 +201,28 @@ public void Update(object obj) /// public void Update(object obj, params object[] parameters) { - Update(obj, true, false, parameters); + Update(obj, true, false, parameters).Wait(); + } + + /// + /// Update a business object. + /// + /// Business object to update. + public async Task UpdateAsync(object obj) + { + await Update(obj, false, false, null).ConfigureAwait(false); + } + + /// + /// Update a business object. + /// + /// Business object to update. + /// + /// Parameters passed to method. + /// + public async Task UpdateAsync(object obj, params object[] parameters) + { + await Update(obj, true, false, parameters).ConfigureAwait(false); } /// @@ -218,7 +231,7 @@ public void Update(object obj, params object[] parameters) /// Business object to update. public void UpdateAll(object obj) { - Update(obj, false, true, null); + Update(obj, false, true, null).Wait(); } /// @@ -230,127 +243,61 @@ public void UpdateAll(object obj) /// public void UpdateAll(object obj, params object[] parameters) { - Update(obj, true, true, parameters); + Update(obj, true, true, parameters).Wait(); } - private void Update(object obj, bool hasParameters, bool bypassIsDirtyTest, params object[] parameters) + /// + /// Update a business object. Include objects which are not dirty. + /// + /// Business object to update. + public async Task UpdateAllAsync(object obj) + { + await Update(obj, false, true, null).ConfigureAwait(false); + } + + /// + /// Update a business object. Include objects which are not dirty. + /// + /// Business object to update. + /// + /// Parameters passed to method. + /// + public async Task UpdateAllAsync(object obj, params object[] parameters) + { + await Update(obj, true, true, parameters).ConfigureAwait(false); + } + + private async Task Update(object obj, bool hasParameters, bool bypassIsDirtyTest, params object[] parameters) { if (obj == null) return; - var busObj = obj as Core.BusinessBase; - if (busObj != null && busObj.IsDirty == false && bypassIsDirtyTest == false) + if (obj is Core.BusinessBase busObj && busObj.IsDirty == false && bypassIsDirtyTest == false) { // if the object isn't dirty, then just exit return; } + var criteria = DataPortal.GetCriteriaFromArray(parameters); var operation = DataPortalOperations.Update; Type objectType = obj.GetType(); - IDataPortalTarget target = obj as IDataPortalTarget; - LateBoundObject lb = new LateBoundObject(obj); + DataPortalTarget lb = new DataPortalTarget(obj); ApplicationContext.DataPortalActivator.InitializeInstance(lb.Instance); try { - if (target != null) - target.Child_OnDataPortalInvoke( - new DataPortalEventArgs(null, objectType, obj, operation)); - else - lb.CallMethodIfImplemented("Child_OnDataPortalInvoke", + lb.Child_OnDataPortalInvoke( + new DataPortalEventArgs(null, objectType, obj, operation)); + await lb.UpdateChildAsync(criteria).ConfigureAwait(false); + lb.Child_OnDataPortalInvokeComplete( new DataPortalEventArgs(null, objectType, obj, operation)); - - // tell the business object to update itself - if (busObj != null) - { - if (busObj.IsDeleted) - { - if (!busObj.IsNew) - { - // tell the object to delete itself - if (hasParameters) - lb.CallMethod("Child_DeleteSelf", parameters); - else - lb.CallMethod("Child_DeleteSelf"); - } - if (target != null) - target.MarkNew(); - else - lb.CallMethodIfImplemented("MarkNew"); - - } - else - { - if (busObj.IsNew) - { - // tell the object to insert itself - if (hasParameters) - lb.CallMethod("Child_Insert", parameters); - else - { - lb.CallMethod("Child_Insert"); - } - - } - else - { - // tell the object to update itself - if (hasParameters) - lb.CallMethod("Child_Update", parameters); - else - { - lb.CallMethod("Child_Update"); - } - } - if (target != null) - target.MarkOld(); - else - lb.CallMethodIfImplemented("MarkOld"); - } - - } - else if (obj is Core.ICommandObject) - { - // tell the object to update itself - if (hasParameters) - lb.CallMethod("Child_Execute", parameters); - else - lb.CallMethod("Child_Execute"); - operation = DataPortalOperations.Execute; - - } - else - { - // this is an updatable collection or some other - // non-BusinessBase type of object - // tell the object to update itself - if (hasParameters) - lb.CallMethod("Child_Update", parameters); - else - lb.CallMethod("Child_Update"); - if (target != null) - target.MarkOld(); - else - lb.CallMethodIfImplemented("MarkOld"); - } - - if (target != null) - target.Child_OnDataPortalInvokeComplete( - new DataPortalEventArgs(null, objectType, obj, operation)); - else - lb.CallMethodIfImplemented("Child_OnDataPortalInvokeComplete", - new DataPortalEventArgs(null, objectType, obj, operation)); - } catch (Exception ex) { try { - if (target != null) - target.Child_OnDataPortalException( - new DataPortalEventArgs(null, objectType, obj, operation), ex); - else if (lb != null) - lb.CallMethodIfImplemented("Child_OnDataPortalException", + if (lb != null) + lb.Child_OnDataPortalException( new DataPortalEventArgs(null, objectType, obj, operation), ex); } catch diff --git a/Source/Csla.Shared/Server/DataPortalTarget.cs b/Source/Csla.Shared/Server/DataPortalTarget.cs index e31f35037c..6f7f44acbe 100644 --- a/Source/Csla.Shared/Server/DataPortalTarget.cs +++ b/Source/Csla.Shared/Server/DataPortalTarget.cs @@ -260,6 +260,71 @@ public async Task UpdateAsync(bool isSync) } } + public async Task UpdateChildAsync(object criteria) + { + // tell the business object to update itself + if (Instance is Core.BusinessBase busObj) + { + if (busObj.IsDeleted) + { + if (!busObj.IsNew) + { + // tell the object to delete itself +#if NET40 + await CallMethodTryAsync(_methodNames.DeleteSelfChild, criteria).ConfigureAwait(false); +#else + await InvokeOperationAsync(criteria, false, typeof(DeleteSelfChildAttribute)).ConfigureAwait(false); +#endif + MarkNew(); + } + } + else + { + if (busObj.IsNew) + { + // tell the object to insert itself +#if NET40 + await CallMethodTryAsync(_methodNames.InsertChild, criteria).ConfigureAwait(false); +#else + await InvokeOperationAsync(criteria, false, typeof(InsertChildAttribute)).ConfigureAwait(false); +#endif + } + else + { + // tell the object to update itself +#if NET40 + await CallMethodTryAsync(_methodNames.UpdateChild, criteria).ConfigureAwait(false); +#else + await InvokeOperationAsync(criteria, false, typeof(UpdateChildAttribute)).ConfigureAwait(false); +#endif + } + MarkOld(); + } + + } + else if (Instance is Core.ICommandObject) + { + // tell the object to update itself +#if NET40 + await CallMethodTryAsync(_methodNames.ExecuteChild, criteria).ConfigureAwait(false); +#else + await InvokeOperationAsync(criteria, false, typeof(ExecuteChildAttribute)).ConfigureAwait(false); +#endif + } + else + { + // this is an updatable collection or some other + // non-BusinessBase type of object + // tell the object to update itself +#if NET40 + await CallMethodTryAsync(_methodNames.UpdateChild, criteria).ConfigureAwait(false); +#else + await InvokeOperationAsync(criteria, false, typeof(UpdateChildAttribute)).ConfigureAwait(false); +#endif + MarkOld(); + } + } + public async Task ExecuteAsync(bool isSync) { #if NET40 @@ -296,6 +361,9 @@ internal class DataPortalMethodNames public string CreateChild { get; set; } = "Child_Create"; public string FetchChild { get; set; } = "Child_Fetch"; public string UpdateChild { get; set; } = "Child_Update"; + public string InsertChild { get; set; } = "Child_Insert"; + public string DeleteSelfChild { get; set; } = "Child_DeleteSelf"; + public string ExecuteChild { get; set; } = "Child_Execute"; public string OnDataPortalInvoke { get; set; } = "DataPortal_OnDataPortalInvoke"; public string OnDataPortalInvokeComplete { get; set; } = "DataPortal_OnDataPortalInvokeComplete"; public string OnDataPortalException { get; set; } = "DataPortal_OnDataPortalException"; diff --git a/Source/csla.netcore.test/DataPortal/ChildDataPortalTests.cs b/Source/csla.netcore.test/DataPortal/ChildDataPortalTests.cs index eeef070956..bd6b1eac34 100644 --- a/Source/csla.netcore.test/DataPortal/ChildDataPortalTests.cs +++ b/Source/csla.netcore.test/DataPortal/ChildDataPortalTests.cs @@ -34,14 +34,6 @@ public async Task CreateChildNoCriteria() Assert.AreEqual("none", child.Name); } - [TestMethod] - public async Task CreateChildNullCriteria() - { - var dp = new Server.ChildDataPortal(); - var child = await dp.CreateAsync(null); - Assert.AreEqual("null", child.Name); - } - [TestMethod] public async Task CreateChildInt32Criteria() { @@ -54,7 +46,7 @@ public async Task CreateChildInt32Criteria() public async Task CreateChildMultipleCriteria() { var dp = new Server.ChildDataPortal(); - var child = await dp.CreateAsync(123, "abc"); + var child = await dp.CreateAsync("abc", 123); Assert.AreEqual("2", child.Name); } @@ -65,14 +57,6 @@ public async Task FetchChildNoCriteria() Assert.AreEqual("none", child.Name); } - [TestMethod] - public async Task FetchChildNullCriteria() - { - var dp = new Server.ChildDataPortal(); - var child = await dp.FetchAsync(null); - Assert.AreEqual("null", child.Name); - } - [TestMethod] public async Task FetchChildInt32Criteria() { @@ -85,9 +69,18 @@ public async Task FetchChildInt32Criteria() public async Task FetchChildMultipleCriteria() { var dp = new Server.ChildDataPortal(); - var child = await dp.FetchAsync(123, "abc"); + var child = await dp.FetchAsync("abc", 123); Assert.AreEqual("2", child.Name); } + + [TestMethod] + public async Task UpdateChild() + { + var dp = new Server.ChildDataPortal(); + var child = await dp.FetchAsync(); + await dp.UpdateAsync(child, "update", 123); + Assert.AreEqual("update/123", child.Name); + } } [Serializable] @@ -108,6 +101,14 @@ private async Task CreateChild() return; } + [CreateChild] + private async Task CreateChild(int i) + { + await Task.Delay(0); + Name = "Int32"; + return; + } + [CreateChild] private async Task CreateChild(object o) { @@ -120,15 +121,10 @@ private async Task CreateChild(object o) } [CreateChild] - private async Task CreateChild(params object[] parameters) + private async Task CreateChild(string s, int i) { await Task.Delay(0); - if (parameters == null) - Name = "null array"; - else if (parameters.Length == 1) - Name = parameters[0].GetType().Name; - else - Name = parameters.Length.ToString(); + Name = "2"; return; } @@ -146,22 +142,40 @@ private async Task FetchChild(object o) await Task.Delay(0); if (o == null) Name = "null"; + else if (o is Int32) + Name = "Int32"; else Name = "bad"; return; } [FetchChild] - private async Task FetchChild(params object[] parameters) + private async Task FetchChild(string s, int i) { await Task.Delay(0); - if (parameters == null) - Name = "null array"; - else if (parameters.Length == 1) - Name = parameters[0].GetType().Name; - else - Name = parameters.Length.ToString(); + Name = "2"; return; } + + [UpdateChild] + private async Task UpdateChild(string s, int i) + { + await Task.Delay(0); + Name = $"{s}/{i}"; + } + + [InsertChild] + private async Task InsertChild(params object[] parameters) + { + await Task.Delay(0); + Name = parameters[0].ToString(); + } + + [DeleteSelfChild] + private async Task DeleteChild(params object[] parameters) + { + await Task.Delay(0); + Name = parameters[0].ToString(); + } } } diff --git a/Source/csla.netcore.test/DataPortal/ServiceProviderInvocationTests.cs b/Source/csla.netcore.test/DataPortal/ServiceProviderInvocationTests.cs index 1a9f4ff49c..8f8081cc9f 100644 --- a/Source/csla.netcore.test/DataPortal/ServiceProviderInvocationTests.cs +++ b/Source/csla.netcore.test/DataPortal/ServiceProviderInvocationTests.cs @@ -75,12 +75,12 @@ public string Speak() public class TestMethods { - public bool Method1(int id, [FromServices]ISpeak speaker) + public bool Method1(int id, [Inject]ISpeak speaker) { return speaker == null; } - public string GetSpeech(int id, [FromServices]ISpeak speaker) + public string GetSpeech(int id, [Inject]ISpeak speaker) { return speaker.Speak(); } diff --git a/Source/csla.netcore.test/DataPortal/ServiceProviderMethodCallerTests.cs b/Source/csla.netcore.test/DataPortal/ServiceProviderMethodCallerTests.cs index 01104f4ee8..40eb36008b 100644 --- a/Source/csla.netcore.test/DataPortal/ServiceProviderMethodCallerTests.cs +++ b/Source/csla.netcore.test/DataPortal/ServiceProviderMethodCallerTests.cs @@ -241,7 +241,7 @@ public class AmbiguousNoCriteriaCreate : BusinessBase private void Create() { } [Create] - private void Create([FromServices] ICloneable x) { } + private void Create([Inject] ICloneable x) { } } [Serializable] @@ -251,7 +251,7 @@ public class CriteriaCreateWithDI : BusinessBase private void Create() { } [Create] - private void Create(int id, [FromServices] ICloneable x) { } + private void Create(int id, [Inject] ICloneable x) { } } [Serializable] @@ -261,30 +261,30 @@ public class MultipleCriteriaCreateWithDI : BusinessBase { [Create] - private void Create(int id, [FromServices] ICloneable x) { } + private void Create(int id, [Inject] ICloneable x) { } [Create] - private void Create(int id, [FromServices] ICloneable x, [FromServices] IAsyncResult y) { } + private void Create(int id, [Inject] ICloneable x, [Inject] IAsyncResult y) { } } [Serializable] public class CriteriaCreateWithMultipleAmbiguousDI : BusinessBase { [Create] - private void Create(int id, [FromServices] ICloneable x) { } + private void Create(int id, [Inject] ICloneable x) { } [Create] - private void Create(int id, [FromServices] ICloneable x, [FromServices] IAsyncResult y) { } + private void Create(int id, [Inject] ICloneable x, [Inject] IAsyncResult y) { } [Create] - private void Create(int id, [FromServices] ICloneable x, [FromServices] IFormattable y) { } + private void Create(int id, [Inject] ICloneable x, [Inject] IFormattable y) { } } [Serializable] @@ -294,6 +294,6 @@ public class MultipleCriteriaCreateWithDIInterleaved : BusinessBase