Commit for development environment setup
This commit is contained in:
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Security.Principal;
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration;
|
||||
using System.Web;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides consistent context information between the client
|
||||
/// and server DataPortal objects.
|
||||
/// </summary>
|
||||
public static class ApplicationContext
|
||||
{
|
||||
#region User
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the current <see cref="IPrincipal" />
|
||||
/// object representing the user's identity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is discussed in Chapter 5. When running
|
||||
/// under IIS the HttpContext.Current.User value
|
||||
/// is used, otherwise the current Thread.CurrentPrincipal
|
||||
/// value is used.
|
||||
/// </remarks>
|
||||
public static IPrincipal User
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
return Thread.CurrentPrincipal;
|
||||
else
|
||||
return HttpContext.Current.User;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.User = value;
|
||||
Thread.CurrentPrincipal = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LocalContext
|
||||
|
||||
private const string _localContextName = "Csla.LocalContext";
|
||||
|
||||
/// <summary>
|
||||
/// Returns the application-specific context data that
|
||||
/// is local to the current AppDomain.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The return value is a HybridDictionary. If one does
|
||||
/// not already exist, and empty one is created and returned.
|
||||
/// </para><para>
|
||||
/// Note that data in this context is NOT transferred to and from
|
||||
/// the client and server.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static HybridDictionary LocalContext
|
||||
{
|
||||
get
|
||||
{
|
||||
HybridDictionary ctx = GetLocalContext();
|
||||
if (ctx == null)
|
||||
{
|
||||
ctx = new HybridDictionary();
|
||||
SetLocalContext(ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
private static HybridDictionary GetLocalContext()
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_localContextName);
|
||||
return (HybridDictionary)Thread.GetData(slot);
|
||||
}
|
||||
else
|
||||
return (HybridDictionary)HttpContext.Current.Items[_localContextName];
|
||||
}
|
||||
|
||||
private static void SetLocalContext(HybridDictionary localContext)
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_localContextName);
|
||||
Thread.SetData(slot, localContext);
|
||||
}
|
||||
else
|
||||
HttpContext.Current.Items[_localContextName] = localContext;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client/Global Context
|
||||
|
||||
private static object _syncClientContext = new object();
|
||||
private const string _clientContextName = "Csla.ClientContext";
|
||||
private const string _globalContextName = "Csla.GlobalContext";
|
||||
|
||||
/// <summary>
|
||||
/// Returns the application-specific context data provided
|
||||
/// by the client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The return value is a HybridDictionary. If one does
|
||||
/// not already exist, and empty one is created and returned.
|
||||
/// </para><para>
|
||||
/// Note that data in this context is transferred from
|
||||
/// the client to the server. No data is transferred from
|
||||
/// the server to the client.
|
||||
/// </para><para>
|
||||
/// This property is thread safe in a Windows client
|
||||
/// setting and on an application server. It is not guaranteed
|
||||
/// to be thread safe within the context of an ASP.NET
|
||||
/// client setting (i.e. in your ASP.NET UI).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static HybridDictionary ClientContext
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_syncClientContext)
|
||||
{
|
||||
HybridDictionary ctx = GetClientContext();
|
||||
if (ctx == null)
|
||||
{
|
||||
ctx = new HybridDictionary();
|
||||
SetClientContext(ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the application-specific context data shared
|
||||
/// on both client and server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The return value is a HybridDictionary. If one does
|
||||
/// not already exist, and empty one is created and returned.
|
||||
/// </para><para>
|
||||
/// Note that data in this context is transferred to and from
|
||||
/// the client and server. Any objects or data in this context
|
||||
/// will be transferred bi-directionally across the network.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static HybridDictionary GlobalContext
|
||||
{
|
||||
get
|
||||
{
|
||||
HybridDictionary ctx = GetGlobalContext();
|
||||
if (ctx == null)
|
||||
{
|
||||
ctx = new HybridDictionary();
|
||||
SetGlobalContext(ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
internal static HybridDictionary GetClientContext()
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
if (ApplicationContext.ExecutionLocation == ExecutionLocations.Client)
|
||||
lock (_syncClientContext)
|
||||
return (HybridDictionary)AppDomain.CurrentDomain.GetData(_clientContextName);
|
||||
else
|
||||
{
|
||||
LocalDataStoreSlot slot =
|
||||
Thread.GetNamedDataSlot(_clientContextName);
|
||||
return (HybridDictionary)Thread.GetData(slot);
|
||||
}
|
||||
}
|
||||
else
|
||||
return (HybridDictionary)
|
||||
HttpContext.Current.Items[_clientContextName];
|
||||
}
|
||||
|
||||
internal static HybridDictionary GetGlobalContext()
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_globalContextName);
|
||||
return (HybridDictionary)Thread.GetData(slot);
|
||||
}
|
||||
else
|
||||
return (HybridDictionary)HttpContext.Current.Items[_globalContextName];
|
||||
}
|
||||
|
||||
private static void SetClientContext(HybridDictionary clientContext)
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
if (ApplicationContext.ExecutionLocation == ExecutionLocations.Client)
|
||||
lock (_syncClientContext)
|
||||
AppDomain.CurrentDomain.SetData(_clientContextName, clientContext);
|
||||
else
|
||||
{
|
||||
LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_clientContextName);
|
||||
Thread.SetData(slot, clientContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
HttpContext.Current.Items[_clientContextName] = clientContext;
|
||||
}
|
||||
|
||||
internal static void SetGlobalContext(HybridDictionary globalContext)
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
LocalDataStoreSlot slot = Thread.GetNamedDataSlot(_globalContextName);
|
||||
Thread.SetData(slot, globalContext);
|
||||
}
|
||||
else
|
||||
HttpContext.Current.Items[_globalContextName] = globalContext;
|
||||
}
|
||||
|
||||
internal static void SetContext(
|
||||
HybridDictionary clientContext,
|
||||
HybridDictionary globalContext)
|
||||
{
|
||||
SetClientContext(clientContext);
|
||||
SetGlobalContext(globalContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all context collections.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
SetContext(null, null);
|
||||
SetLocalContext(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Config Settings
|
||||
|
||||
/// <summary>
|
||||
/// Returns the authentication type being used by the
|
||||
/// CSLA .NET framework.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This value is read from the application configuration
|
||||
/// file with the key value "CslaAuthentication". The value
|
||||
/// "Windows" indicates CSLA .NET should use Windows integrated
|
||||
/// (or AD) security. Any other value indicates the use of
|
||||
/// custom security derived from BusinessPrincipalBase.
|
||||
/// </remarks>
|
||||
public static string AuthenticationType
|
||||
{
|
||||
get { return ConfigurationManager.AppSettings["CslaAuthentication"]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the channel or network protocol
|
||||
/// for the DataPortal server.
|
||||
/// </summary>
|
||||
/// <value>Fully qualified assembly/type name of the proxy class.</value>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This value is read from the application configuration
|
||||
/// file with the key value "CslaDataPortalProxy".
|
||||
/// </para><para>
|
||||
/// The proxy class must implement Csla.Server.IDataPortalServer.
|
||||
/// </para><para>
|
||||
/// The value "Local" is a shortcut to running the DataPortal
|
||||
/// "server" in the client process.
|
||||
/// </para><para>
|
||||
/// Other built-in values include:
|
||||
/// <list>
|
||||
/// <item>
|
||||
/// <term>Csla,Csla.DataPortalClient.RemotingProxy</term>
|
||||
/// <description>Use .NET Remoting to communicate with the server</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Csla,Csla.DataPortalClient.EnterpriseServicesProxy</term>
|
||||
/// <description>Use Enterprise Services (DCOM) to communicate with the server</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Csla,Csla.DataPortalClient.WebServicesProxy</term>
|
||||
/// <description>Use Web Services (asmx) to communicate with the server</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// Each proxy type does require that the DataPortal server be hosted using the appropriate
|
||||
/// technology. For instance, Web Services and Remoting should be hosted in IIS, while
|
||||
/// Enterprise Services must be hosted in COM+.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static string DataPortalProxy
|
||||
{
|
||||
get
|
||||
{
|
||||
string result = ConfigurationManager.AppSettings["CslaDataPortalProxy"];
|
||||
if (string.IsNullOrEmpty(result))
|
||||
result = "Local";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the URL for the DataPortal server.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This value is read from the application configuration
|
||||
/// file with the key value "CslaDataPortalUrl".
|
||||
/// </remarks>
|
||||
public static Uri DataPortalUrl
|
||||
{
|
||||
get { return new Uri(ConfigurationManager.AppSettings["CslaDataPortalUrl"]); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum representing the locations code can execute.
|
||||
/// </summary>
|
||||
public enum ExecutionLocations
|
||||
{
|
||||
/// <summary>
|
||||
/// The code is executing on the client.
|
||||
/// </summary>
|
||||
Client,
|
||||
/// <summary>
|
||||
/// The code is executing on the application server.
|
||||
/// </summary>
|
||||
Server
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region In-Memory Settings
|
||||
|
||||
private static ExecutionLocations _executionLocation =
|
||||
ExecutionLocations.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the application code
|
||||
/// is currently executing on the client or server.
|
||||
/// </summary>
|
||||
public static ExecutionLocations ExecutionLocation
|
||||
{
|
||||
get { return _executionLocation; }
|
||||
}
|
||||
|
||||
internal static void SetExecutionLocation(ExecutionLocations location)
|
||||
{
|
||||
_executionLocation = location;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,448 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.Runtime.Remoting.Channels.Http;
|
||||
using Csla.Properties;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is the client-side DataPortal as described in
|
||||
/// Chapter 4.
|
||||
/// </summary>
|
||||
public static class DataPortal
|
||||
{
|
||||
|
||||
#region DataPortal events
|
||||
|
||||
/// <summary>
|
||||
/// Raised by DataPortal prior to calling the
|
||||
/// requested server-side DataPortal method.
|
||||
/// </summary>
|
||||
public static event Action<DataPortalEventArgs> DataPortalInvoke;
|
||||
|
||||
/// <summary>
|
||||
/// Raised by DataPortal after the requested
|
||||
/// server-side DataPortal method call is complete.
|
||||
/// </summary>
|
||||
public static event Action<DataPortalEventArgs> DataPortalInvokeComplete;
|
||||
|
||||
private static void OnDataPortalInvoke(DataPortalEventArgs e)
|
||||
{
|
||||
Action<DataPortalEventArgs> action = DataPortalInvoke;
|
||||
if (action != null)
|
||||
action(e);
|
||||
}
|
||||
|
||||
private static void OnDataPortalInvokeComplete(DataPortalEventArgs e)
|
||||
{
|
||||
Action<DataPortalEventArgs> action = DataPortalInvokeComplete;
|
||||
if (action != null)
|
||||
action(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Access methods
|
||||
|
||||
private const int EmptyCriteria = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to create
|
||||
/// a new object, which is loaded with default
|
||||
/// values from the database.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Specific type of the business object.</typeparam>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <returns>A new object, populated with default values.</returns>
|
||||
public static T Create<T>(object criteria)
|
||||
{
|
||||
return (T)Create(typeof(T), criteria);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to create
|
||||
/// a new object, which is loaded with default
|
||||
/// values from the database.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Specific type of the business object.</typeparam>
|
||||
/// <returns>A new object, populated with default values.</returns>
|
||||
public static T Create<T>()
|
||||
{
|
||||
return (T)Create(typeof(T), EmptyCriteria);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to create
|
||||
/// a new object, which is loaded with default
|
||||
/// values from the database.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <returns>A new object, populated with default values.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2223:MembersShouldDifferByMoreThanReturnType")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
public static object Create(object criteria)
|
||||
{
|
||||
return Create(MethodCaller.GetObjectType(criteria), criteria);
|
||||
}
|
||||
|
||||
private static object Create(Type objectType, object criteria)
|
||||
{
|
||||
Server.DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetCreateMethod(objectType, criteria);
|
||||
|
||||
DataPortalClient.IDataPortalProxy proxy;
|
||||
proxy = GetDataPortalProxy(RunLocal(method));
|
||||
|
||||
Server.DataPortalContext dpContext =
|
||||
new Csla.Server.DataPortalContext(GetPrincipal(), proxy.IsServerRemote);
|
||||
|
||||
OnDataPortalInvoke(new DataPortalEventArgs(dpContext));
|
||||
|
||||
try
|
||||
{
|
||||
result = proxy.Create(objectType, criteria, dpContext);
|
||||
}
|
||||
catch (Server.DataPortalException ex)
|
||||
{
|
||||
result = ex.Result;
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
throw new DataPortalException(
|
||||
string.Format("DataPortal.Create {0} ({1})", Resources.Failed, ex.InnerException.InnerException),
|
||||
ex.InnerException, result.ReturnObject);
|
||||
}
|
||||
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
|
||||
OnDataPortalInvokeComplete(new DataPortalEventArgs(dpContext));
|
||||
|
||||
return result.ReturnObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to retrieve
|
||||
/// an object, which is loaded with values from the database.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Specific type of the business object.</typeparam>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <returns>An object populated with values from the database.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2223:MembersShouldDifferByMoreThanReturnType")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static T Fetch<T>(object criteria)
|
||||
{
|
||||
return (T)Fetch(typeof(T), criteria);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to retrieve
|
||||
/// an object, which is loaded with values from the database.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Specific type of the business object.</typeparam>
|
||||
/// <returns>An object populated with values from the database.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2223:MembersShouldDifferByMoreThanReturnType")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static T Fetch<T>()
|
||||
{
|
||||
return (T)Fetch(typeof(T), EmptyCriteria);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a factory method in a business class to retrieve
|
||||
/// an object, which is loaded with values from the database.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <returns>An object populated with values from the database.</returns>
|
||||
public static object Fetch(object criteria)
|
||||
{
|
||||
return Fetch(MethodCaller.GetObjectType(criteria), criteria);
|
||||
}
|
||||
|
||||
private static object Fetch(Type objectType, object criteria)
|
||||
{
|
||||
Server.DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetFetchMethod(objectType, criteria);
|
||||
|
||||
DataPortalClient.IDataPortalProxy proxy;
|
||||
proxy = GetDataPortalProxy(RunLocal(method));
|
||||
|
||||
Server.DataPortalContext dpContext =
|
||||
new Server.DataPortalContext(GetPrincipal(),
|
||||
proxy.IsServerRemote);
|
||||
|
||||
OnDataPortalInvoke(new DataPortalEventArgs(dpContext));
|
||||
|
||||
try
|
||||
{
|
||||
result = proxy.Fetch(objectType, criteria, dpContext);
|
||||
}
|
||||
catch (Server.DataPortalException ex)
|
||||
{
|
||||
result = ex.Result;
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
throw new DataPortalException(
|
||||
String.Format("DataPortal.Fetch {0} ({1})", Resources.Failed, ex.InnerException.InnerException),
|
||||
ex.InnerException, result.ReturnObject);
|
||||
}
|
||||
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
|
||||
OnDataPortalInvokeComplete(new DataPortalEventArgs(dpContext));
|
||||
|
||||
return result.ReturnObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to execute a Command object on the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// To be a Command object, the object must inherit from
|
||||
/// <see cref="CommandBase">CommandBase</see>.
|
||||
/// </para><para>
|
||||
/// Note that this method returns a reference to the updated business object.
|
||||
/// If the server-side DataPortal is running remotely, this will be a new and
|
||||
/// different object from the original, and all object references MUST be updated
|
||||
/// to use this new object.
|
||||
/// </para><para>
|
||||
/// On the server, the Command object's DataPortal_Execute() method will
|
||||
/// be invoked. Write any server-side code in that method.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Specific type of the Command object.</typeparam>
|
||||
/// <param name="obj">A reference to the Command object to be executed.</param>
|
||||
/// <returns>A reference to the updated Command object.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters",
|
||||
MessageId="Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static T Execute<T>(T obj) where T : CommandBase
|
||||
{
|
||||
return (T)Update(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to execute a Command object on the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Note that this method returns a reference to the updated business object.
|
||||
/// If the server-side DataPortal is running remotely, this will be a new and
|
||||
/// different object from the original, and all object references MUST be updated
|
||||
/// to use this new object.
|
||||
/// </para><para>
|
||||
/// On the server, the Command object's DataPortal_Execute() method will
|
||||
/// be invoked. Write any server-side code in that method.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="obj">A reference to the Command object to be executed.</param>
|
||||
/// <returns>A reference to the updated Command object.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId="Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static CommandBase Execute(CommandBase obj)
|
||||
{
|
||||
return (CommandBase)Update(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the business object's Save() method to
|
||||
/// insert, update or delete an object in the database.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that this method returns a reference to the updated business object.
|
||||
/// If the server-side DataPortal is running remotely, this will be a new and
|
||||
/// different object from the original, and all object references MUST be updated
|
||||
/// to use this new object.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">Specific type of the business object.</typeparam>
|
||||
/// <param name="obj">A reference to the business object to be updated.</param>
|
||||
/// <returns>A reference to the updated business object.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static T Update<T>(T obj)
|
||||
{
|
||||
return (T)Update((object)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the business object's Save() method to
|
||||
/// insert, update or delete an object in the database.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that this method returns a reference to the updated business object.
|
||||
/// If the server-side DataPortal is running remotely, this will be a new and
|
||||
/// different object from the original, and all object references MUST be updated
|
||||
/// to use this new object.
|
||||
/// </remarks>
|
||||
/// <param name="obj">A reference to the business object to be updated.</param>
|
||||
/// <returns>A reference to the updated business object.</returns>
|
||||
public static object Update(object obj)
|
||||
{
|
||||
Server.DataPortalResult result;
|
||||
|
||||
MethodInfo method;
|
||||
string methodName;
|
||||
if (obj is CommandBase)
|
||||
methodName = "DataPortal_Execute";
|
||||
else if (obj is Core.BusinessBase)
|
||||
{
|
||||
Core.BusinessBase tmp = (Core.BusinessBase)obj;
|
||||
if (tmp.IsDeleted)
|
||||
methodName = "DataPortal_DeleteSelf";
|
||||
else
|
||||
if (tmp.IsNew)
|
||||
methodName = "DataPortal_Insert";
|
||||
else
|
||||
methodName = "DataPortal_Update";
|
||||
}
|
||||
else
|
||||
methodName = "DataPortal_Update";
|
||||
|
||||
method = MethodCaller.GetMethod(obj.GetType(), methodName);
|
||||
|
||||
DataPortalClient.IDataPortalProxy proxy;
|
||||
proxy = GetDataPortalProxy(RunLocal(method));
|
||||
|
||||
Server.DataPortalContext dpContext =
|
||||
new Server.DataPortalContext(GetPrincipal(), proxy.IsServerRemote);
|
||||
|
||||
OnDataPortalInvoke(new DataPortalEventArgs(dpContext));
|
||||
|
||||
try
|
||||
{
|
||||
result = proxy.Update(obj, dpContext);
|
||||
}
|
||||
catch (Server.DataPortalException ex)
|
||||
{
|
||||
result = ex.Result;
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
throw new DataPortalException(
|
||||
String.Format("DataPortal.Update {0} ({1})", Resources.Failed, ex.InnerException.InnerException),
|
||||
ex.InnerException, result.ReturnObject);
|
||||
}
|
||||
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
|
||||
OnDataPortalInvokeComplete(new DataPortalEventArgs(dpContext));
|
||||
|
||||
return result.ReturnObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by a Shared (static in C#) method in the business class to cause
|
||||
/// immediate deletion of a specific object from the database.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.DataPortalException.#ctor(System.String,System.Exception,System.Object)")]
|
||||
public static void Delete(object criteria)
|
||||
{
|
||||
Server.DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetMethod(
|
||||
MethodCaller.GetObjectType(criteria), "DataPortal_Delete", criteria);
|
||||
|
||||
DataPortalClient.IDataPortalProxy proxy;
|
||||
proxy = GetDataPortalProxy(RunLocal(method));
|
||||
|
||||
Server.DataPortalContext dpContext = new Server.DataPortalContext(GetPrincipal(), proxy.IsServerRemote);
|
||||
|
||||
OnDataPortalInvoke(new DataPortalEventArgs(dpContext));
|
||||
|
||||
try
|
||||
{
|
||||
result = proxy.Delete(criteria, dpContext);
|
||||
}
|
||||
catch (Server.DataPortalException ex)
|
||||
{
|
||||
result = ex.Result;
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
throw new DataPortalException(
|
||||
String.Format("DataPortal.Delete {0} ({1})", Resources.Failed, ex.InnerException.InnerException),
|
||||
ex.InnerException, result.ReturnObject);
|
||||
}
|
||||
|
||||
if (proxy.IsServerRemote)
|
||||
ApplicationContext.SetGlobalContext(result.GlobalContext);
|
||||
|
||||
OnDataPortalInvokeComplete(new DataPortalEventArgs(dpContext));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DataPortal Proxy
|
||||
|
||||
private static DataPortalClient.IDataPortalProxy _localPortal;
|
||||
private static DataPortalClient.IDataPortalProxy _portal;
|
||||
|
||||
private static DataPortalClient.IDataPortalProxy GetDataPortalProxy(bool forceLocal)
|
||||
{
|
||||
if (forceLocal)
|
||||
{
|
||||
if (_localPortal == null)
|
||||
_localPortal = new DataPortalClient.LocalProxy();
|
||||
return _localPortal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_portal == null)
|
||||
{
|
||||
string proxyTypeName = ApplicationContext.DataPortalProxy;
|
||||
if (proxyTypeName == "Local")
|
||||
_portal = new DataPortalClient.LocalProxy();
|
||||
else
|
||||
{
|
||||
string typeName =
|
||||
proxyTypeName.Substring(0, proxyTypeName.IndexOf(",")).Trim();
|
||||
string assemblyName =
|
||||
proxyTypeName.Substring(proxyTypeName.IndexOf(",") + 1).Trim();
|
||||
_portal = (DataPortalClient.IDataPortalProxy)
|
||||
Activator.CreateInstance(assemblyName, typeName).Unwrap();
|
||||
}
|
||||
}
|
||||
return _portal;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Security
|
||||
|
||||
private static System.Security.Principal.IPrincipal GetPrincipal()
|
||||
{
|
||||
if (ApplicationContext.AuthenticationType == "Windows")
|
||||
{
|
||||
// Windows integrated security
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we assume using the CSLA framework security
|
||||
return ApplicationContext.User;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper methods
|
||||
|
||||
private static bool RunLocal(MethodInfo method)
|
||||
{
|
||||
return Attribute.IsDefined(method, typeof(RunLocalAttribute), false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.DataPortalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a data portal proxy to relay data portal
|
||||
/// calls to an application server hosted in COM+.
|
||||
/// </summary>
|
||||
public abstract class EnterpriseServicesProxy : DataPortalClient.IDataPortalProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Override this method to return a reference to
|
||||
/// the server-side COM+ (ServicedComponent) object
|
||||
/// implementing the data portal server functionality.
|
||||
/// </summary>
|
||||
protected abstract Server.Hosts.EnterpriseServicesPortal GetServerObject();
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to create a
|
||||
/// new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual Server.DataPortalResult Create(Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
Server.Hosts.EnterpriseServicesPortal svc = GetServerObject();
|
||||
try
|
||||
{
|
||||
return svc.Create(objectType, criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (svc != null)
|
||||
svc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to load an
|
||||
/// existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual Server.DataPortalResult Fetch(Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
Server.Hosts.EnterpriseServicesPortal svc = GetServerObject();
|
||||
try
|
||||
{
|
||||
return svc.Fetch(objectType, criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (svc != null)
|
||||
svc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to update a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual Server.DataPortalResult Update(object obj, Server.DataPortalContext context)
|
||||
{
|
||||
Server.Hosts.EnterpriseServicesPortal svc = GetServerObject();
|
||||
try
|
||||
{
|
||||
return svc.Update(obj, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (svc != null)
|
||||
svc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to delete a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual Server.DataPortalResult Delete(object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
Server.Hosts.EnterpriseServicesPortal svc = GetServerObject();
|
||||
try
|
||||
{
|
||||
return svc.Delete(criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (svc != null)
|
||||
svc.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating whether this proxy will invoke
|
||||
/// a remote data portal server, or run the "server-side"
|
||||
/// data portal in the caller's process and AppDomain.
|
||||
/// </summary>
|
||||
public virtual bool IsServerRemote
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.DataPortalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface implemented by client-side
|
||||
/// data portal proxy objects.
|
||||
/// </summary>
|
||||
public interface IDataPortalProxy : Server.IDataPortalServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a value indicating whether this proxy will invoke
|
||||
/// a remote data portal server, or run the "server-side"
|
||||
/// data portal in the caller's process and AppDomain.
|
||||
/// </summary>
|
||||
bool IsServerRemote { get;}
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Csla.Server;
|
||||
|
||||
namespace Csla.DataPortalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a data portal proxy to relay data portal
|
||||
/// calls to an application server hosted locally
|
||||
/// in the client process and AppDomain.
|
||||
/// </summary>
|
||||
public class LocalProxy : DataPortalClient.IDataPortalProxy
|
||||
{
|
||||
private Server.IDataPortalServer _portal =
|
||||
new Server.DataPortal();
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to create a
|
||||
/// new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Create(
|
||||
Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
return _portal.Create(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to load an
|
||||
/// existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
return _portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to update a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
return _portal.Update(obj, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to delete a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
return _portal.Delete(criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating whether this proxy will invoke
|
||||
/// a remote data portal server, or run the "server-side"
|
||||
/// data portal in the caller's process and AppDomain.
|
||||
/// </summary>
|
||||
public bool IsServerRemote
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.Runtime.Remoting.Channels.Http;
|
||||
|
||||
namespace Csla.DataPortalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a data portal proxy to relay data portal
|
||||
/// calls to a remote application server by using the
|
||||
/// .NET Remoting technology.
|
||||
/// </summary>
|
||||
public class RemotingProxy : DataPortalClient.IDataPortalProxy
|
||||
{
|
||||
|
||||
#region Configure Remoting
|
||||
|
||||
/// <summary>
|
||||
/// Configure .NET Remoting to use a binary
|
||||
/// serialization technology even when using
|
||||
/// the HTTP channel. Also ensures that the
|
||||
/// user's Windows credentials are passed to
|
||||
/// the server appropriately.
|
||||
/// </summary>
|
||||
static RemotingProxy()
|
||||
{
|
||||
// create and register a custom HTTP channel
|
||||
// that uses the binary formatter
|
||||
Hashtable properties = new Hashtable();
|
||||
properties["name"] = "HttpBinary";
|
||||
|
||||
if (ApplicationContext.AuthenticationType == "Windows" || AlwaysImpersonate)
|
||||
{
|
||||
// make sure we pass the user's Windows credentials
|
||||
// to the server
|
||||
properties["useDefaultCredentials"] = true;
|
||||
}
|
||||
|
||||
BinaryClientFormatterSinkProvider
|
||||
formatter = new BinaryClientFormatterSinkProvider();
|
||||
HttpChannel channel = new HttpChannel(properties, formatter, null);
|
||||
ChannelServices.RegisterChannel(channel, EncryptChannel);
|
||||
}
|
||||
|
||||
private static bool AlwaysImpersonate
|
||||
{
|
||||
get
|
||||
{
|
||||
bool result =
|
||||
(ConfigurationManager.AppSettings["AlwaysImpersonate"] == "true");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool EncryptChannel
|
||||
{
|
||||
get
|
||||
{
|
||||
bool encrypt =
|
||||
(ConfigurationManager.AppSettings["CslaEncryptRemoting"] == "true");
|
||||
return encrypt;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Server.IDataPortalServer _portal;
|
||||
|
||||
private Server.IDataPortalServer Portal
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_portal == null)
|
||||
_portal = (Server.IDataPortalServer)Activator.GetObject(
|
||||
typeof(Server.Hosts.RemotingPortal),
|
||||
ApplicationContext.DataPortalUrl.ToString());
|
||||
return _portal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to create a
|
||||
/// new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Create(
|
||||
Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
return Portal.Create(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to load an
|
||||
/// existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Fetch(Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
return Portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to update a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Update(object obj, Server.DataPortalContext context)
|
||||
{
|
||||
return Portal.Update(obj, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to delete a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Delete(object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
return Portal.Delete(criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating whether this proxy will invoke
|
||||
/// a remote data portal server, or run the "server-side"
|
||||
/// data portal in the caller's process and AppDomain.
|
||||
/// </summary>
|
||||
public bool IsServerRemote
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using Csla.WebServiceHost;
|
||||
|
||||
namespace Csla.DataPortalClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a data portal proxy to relay data portal
|
||||
/// calls to a remote application server by using
|
||||
/// Web services.
|
||||
/// </summary>
|
||||
public class WebServicesProxy : DataPortalClient.IDataPortalProxy
|
||||
{
|
||||
private WebServiceHost.WebServicePortal GetPortal()
|
||||
{
|
||||
WebServiceHost.WebServicePortal wsvc =
|
||||
new WebServiceHost.WebServicePortal();
|
||||
wsvc.Url = ApplicationContext.DataPortalUrl.ToString();
|
||||
return wsvc;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to create a
|
||||
/// new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Create(
|
||||
Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
object result;
|
||||
Csla.Server.Hosts.WebServicePortal.CreateRequest
|
||||
request = new Csla.Server.Hosts.WebServicePortal.CreateRequest();
|
||||
request.ObjectType = objectType;
|
||||
request.Criteria = criteria;
|
||||
request.Context = context;
|
||||
|
||||
using (WebServiceHost.WebServicePortal wsvc = GetPortal())
|
||||
{
|
||||
byte[] rd = Serialize(request);
|
||||
byte[] rp = wsvc.Create(rd);
|
||||
result = Deserialize(rp);
|
||||
}
|
||||
|
||||
if (result is Exception)
|
||||
throw (Exception)result;
|
||||
return (Server.DataPortalResult)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to load an
|
||||
/// existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Fetch(
|
||||
Type objectType, object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
object result;
|
||||
Server.Hosts.WebServicePortal.FetchRequest request =
|
||||
new Server.Hosts.WebServicePortal.FetchRequest();
|
||||
request.ObjectType = objectType;
|
||||
request.Criteria = criteria;
|
||||
request.Context = context;
|
||||
|
||||
using (WebServiceHost.WebServicePortal wsvc = GetPortal())
|
||||
{
|
||||
result = Deserialize(wsvc.Fetch(Serialize(request)));
|
||||
}
|
||||
|
||||
if (result is Exception)
|
||||
throw (Exception)result;
|
||||
return (Server.DataPortalResult)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to update a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Update(object obj, Server.DataPortalContext context)
|
||||
{
|
||||
object result;
|
||||
Server.Hosts.WebServicePortal.UpdateRequest request = new Server.Hosts.WebServicePortal.UpdateRequest();
|
||||
request.Object = obj;
|
||||
request.Context = context;
|
||||
|
||||
using (WebServiceHost.WebServicePortal wsvc = GetPortal())
|
||||
{
|
||||
result = Deserialize(wsvc.Update(Serialize(request)));
|
||||
}
|
||||
|
||||
if (result is Exception)
|
||||
throw (Exception)result;
|
||||
return (Server.DataPortalResult)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="DataPortal" /> to delete a
|
||||
/// business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public Server.DataPortalResult Delete(object criteria, Server.DataPortalContext context)
|
||||
{
|
||||
object result;
|
||||
Server.Hosts.WebServicePortal.DeleteRequest request = new Server.Hosts.WebServicePortal.DeleteRequest();
|
||||
request.Criteria = criteria;
|
||||
request.Context = context;
|
||||
|
||||
using (WebServiceHost.WebServicePortal wsvc = GetPortal())
|
||||
{
|
||||
result = Deserialize(wsvc.Delete(Serialize(request)));
|
||||
}
|
||||
|
||||
if (result is Exception)
|
||||
throw (Exception)result;
|
||||
return (Server.DataPortalResult)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a value indicating whether this proxy will invoke
|
||||
/// a remote data portal server, or run the "server-side"
|
||||
/// data portal in the caller's process and AppDomain.
|
||||
/// </summary>
|
||||
public bool IsServerRemote
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
|
||||
#region Helper functions
|
||||
|
||||
private static byte[] Serialize(object obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
using (MemoryStream buffer = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(buffer, obj);
|
||||
return buffer.ToArray();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object Deserialize(byte[] obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
using (MemoryStream buffer = new MemoryStream(obj))
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
return formatter.Deserialize(buffer);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Base type from which Criteria classes can be
|
||||
/// derived in a business class.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public abstract class CriteriaBase
|
||||
{
|
||||
private Type _objectType;
|
||||
|
||||
/// <summary>
|
||||
/// Type of the business object to be instantiated by
|
||||
/// the server-side DataPortal.
|
||||
/// </summary>
|
||||
public Type ObjectType
|
||||
{
|
||||
get { return _objectType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes CriteriaBase with the type of
|
||||
/// business object to be created by the DataPortal.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of the
|
||||
/// business object the data portal should create.</param>
|
||||
protected CriteriaBase(Type type)
|
||||
{
|
||||
_objectType = type;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information about the DataPortal
|
||||
/// call.
|
||||
/// </summary>
|
||||
public class DataPortalEventArgs : EventArgs
|
||||
{
|
||||
private Server.DataPortalContext _dataPortalContext;
|
||||
|
||||
/// <summary>
|
||||
/// The DataPortalContext object passed to the
|
||||
/// server-side DataPortal.
|
||||
/// </summary>
|
||||
public Server.DataPortalContext DataPortalContext
|
||||
{
|
||||
get { return _dataPortalContext; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="dataPortalContext">
|
||||
/// Data portal context object.
|
||||
/// </param>
|
||||
public DataPortalEventArgs(Server.DataPortalContext dataPortalContext)
|
||||
{
|
||||
_dataPortalContext = dataPortalContext;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This exception is returned for any errors occuring
|
||||
/// during the server-side DataPortal invocation.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
|
||||
[Serializable()]
|
||||
public class DataPortalException : Exception
|
||||
{
|
||||
private object _businessObject;
|
||||
private string _innerStackTrace;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a reference to the business object
|
||||
/// from the server-side DataPortal.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Remember that this object may be in an invalid
|
||||
/// or undefined state. This is the business object
|
||||
/// (and any child objects) as it existed when the
|
||||
/// exception occured on the server. Thus the object
|
||||
/// state may have been altered by the server and
|
||||
/// may no longer reflect data in the database.
|
||||
/// </remarks>
|
||||
public object BusinessObject
|
||||
{
|
||||
get { return _businessObject; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original server-side exception.
|
||||
/// </summary>
|
||||
/// <returns>An exception object.</returns>
|
||||
/// <remarks>
|
||||
/// When an exception occurs in business code behind
|
||||
/// the data portal, it is wrapped in a
|
||||
/// <see cref="Csla.Server.DataPortalException"/>, which
|
||||
/// is then wrapped in a
|
||||
/// <see cref="Csla.DataPortalException"/>. This property
|
||||
/// unwraps and returns the original exception
|
||||
/// thrown by the business code on the server.
|
||||
/// </remarks>
|
||||
public Exception BusinessException
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.InnerException.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the combined stack trace from the server
|
||||
/// and client.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)")]
|
||||
public override string StackTrace
|
||||
{
|
||||
get { return String.Format("{0}{1}{2}", _innerStackTrace, Environment.NewLine, base.StackTrace); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Text describing the exception.</param>
|
||||
/// <param name="businessObject">The business object
|
||||
/// as it was at the time of the exception.</param>
|
||||
public DataPortalException(string message, object businessObject)
|
||||
: base(message)
|
||||
{
|
||||
_innerStackTrace = String.Empty;
|
||||
_businessObject = businessObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Text describing the exception.</param>
|
||||
/// <param name="ex">Inner exception.</param>
|
||||
/// <param name="businessObject">The business object
|
||||
/// as it was at the time of the exception.</param>
|
||||
public DataPortalException(string message, Exception ex, object businessObject)
|
||||
: base(message, ex)
|
||||
{
|
||||
_innerStackTrace = ex.StackTrace;
|
||||
_businessObject = businessObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object for serialization.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialiation info object.</param>
|
||||
/// <param name="context">Serialization context object.</param>
|
||||
protected DataPortalException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
_businessObject = info.GetValue("_businessObject", typeof(object));
|
||||
_innerStackTrace = info.GetString("_innerStackTrace");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the object.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialiation info object.</param>
|
||||
/// <param name="context">Serialization context object.</param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("_businessObject", _businessObject);
|
||||
info.AddValue("_innerStackTrace", _innerStackTrace);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.EnterpriseServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Csla.Server.Hosts
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Exposes server-side DataPortal functionality
|
||||
/// through Enterprise Services.
|
||||
/// </summary>
|
||||
[EventTrackingEnabled(true)]
|
||||
[ComVisible(true)]
|
||||
public abstract class EnterpriseServicesPortal : ServicedComponent, Server.IDataPortalServer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Set up event handler to deal with
|
||||
/// serialization issue as discussed
|
||||
/// in Chapter 4.
|
||||
/// </summary>
|
||||
static EnterpriseServicesPortal()
|
||||
{
|
||||
SerializationWorkaround();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual DataPortalResult Create(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new Server.DataPortal();
|
||||
return portal.Create(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new Server.DataPortal();
|
||||
return portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new Server.DataPortal();
|
||||
return portal.Update(obj, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public virtual DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new Server.DataPortal();
|
||||
return portal.Delete(criteria, context);
|
||||
}
|
||||
|
||||
#region Serialization bug workaround
|
||||
|
||||
private static void SerializationWorkaround()
|
||||
{
|
||||
// hook up the AssemblyResolve
|
||||
// event so deep serialization works properly
|
||||
// this is a workaround for a bug in the .NET runtime
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
|
||||
currentDomain.AssemblyResolve +=
|
||||
new ResolveEventHandler(ResolveEventHandler);
|
||||
}
|
||||
|
||||
private static Assembly ResolveEventHandler(
|
||||
object sender, ResolveEventArgs args)
|
||||
{
|
||||
// get a list of all the assemblies loaded in our appdomain
|
||||
Assembly[] list = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
// search the list to find the assembly that was not found automatically
|
||||
// and return the assembly from the list
|
||||
|
||||
foreach (Assembly asm in list)
|
||||
if (asm.FullName == args.Name)
|
||||
return asm;
|
||||
|
||||
// if the assembly wasn't already in the appdomain, then try to load it.
|
||||
return Assembly.Load(args.Name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
|
||||
namespace Csla.Server.Hosts
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes server-side DataPortal functionality
|
||||
/// through .NET Remoting.
|
||||
/// </summary>
|
||||
public class RemotingPortal : MarshalByRefObject, Server.IDataPortalServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Create(
|
||||
Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new DataPortal();
|
||||
return portal.Create(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new DataPortal();
|
||||
return portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new DataPortal();
|
||||
return portal.Update(obj, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
Server.DataPortal portal = new DataPortal();
|
||||
return portal.Delete(criteria, context);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Services;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace Csla.Server.Hosts
|
||||
{
|
||||
// in asmx use web directive like
|
||||
// <%@ WebService Class="Csla.Server.Hosts.WebServicePortal" %>
|
||||
/// <summary>
|
||||
/// Exposes server-side DataPortal functionality
|
||||
/// through Web Services (asmx).
|
||||
/// </summary>
|
||||
[WebService(Namespace = "http://ws.lhotka.net/Csla")]
|
||||
public class WebServicePortal : WebService
|
||||
{
|
||||
|
||||
#region Request classes
|
||||
|
||||
/// <summary>
|
||||
/// Request message for creating
|
||||
/// a new business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class CreateRequest
|
||||
{
|
||||
private Type _objectType;
|
||||
private object _criteria;
|
||||
private Server.DataPortalContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Type of business object to create.
|
||||
/// </summary>
|
||||
public Type ObjectType
|
||||
{
|
||||
get { return _objectType; }
|
||||
set { _objectType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Criteria object describing business object.
|
||||
/// </summary>
|
||||
public object Criteria
|
||||
{
|
||||
get { return _criteria; }
|
||||
set { _criteria = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data portal context from client.
|
||||
/// </summary>
|
||||
public Server.DataPortalContext Context
|
||||
{
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request message for retrieving
|
||||
/// an existing business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class FetchRequest
|
||||
{
|
||||
private Type _objectType;
|
||||
private object _criteria;
|
||||
private Server.DataPortalContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Type of business object to create.
|
||||
/// </summary>
|
||||
public Type ObjectType
|
||||
{
|
||||
get { return _objectType; }
|
||||
set { _objectType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Criteria object describing business object.
|
||||
/// </summary>
|
||||
public object Criteria
|
||||
{
|
||||
get { return _criteria; }
|
||||
set { _criteria = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data portal context from client.
|
||||
/// </summary>
|
||||
public Server.DataPortalContext Context
|
||||
{
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request message for updating
|
||||
/// a business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class UpdateRequest
|
||||
{
|
||||
private object _object;
|
||||
private Server.DataPortalContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Business object to be updated.
|
||||
/// </summary>
|
||||
public object Object
|
||||
{
|
||||
get { return _object; }
|
||||
set { _object = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data portal context from client.
|
||||
/// </summary>
|
||||
public Server.DataPortalContext Context
|
||||
{
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request message for deleting
|
||||
/// a business object.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class DeleteRequest
|
||||
{
|
||||
private object _criteria;
|
||||
private Server.DataPortalContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// Criteria object describing business object.
|
||||
/// </summary>
|
||||
public object Criteria
|
||||
{
|
||||
get { return _criteria; }
|
||||
set { _criteria = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data portal context from client.
|
||||
/// </summary>
|
||||
public Server.DataPortalContext Context
|
||||
{
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="requestData">Byte stream containing <see cref="CreateRequest" />.</param>
|
||||
/// <returns>Byte stream containing resulting object data.</returns>
|
||||
[WebMethod()]
|
||||
public byte[] Create(byte[] requestData)
|
||||
{
|
||||
CreateRequest request = (CreateRequest)Deserialize(requestData);
|
||||
|
||||
DataPortal portal = new DataPortal();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = portal.Create(request.ObjectType, request.Criteria, request.Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result = ex;
|
||||
}
|
||||
return Serialize(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="requestData">Byte stream containing <see cref="FetchRequest" />.</param>
|
||||
/// <returns>Byte stream containing resulting object data.</returns>
|
||||
[WebMethod()]
|
||||
public byte[] Fetch(byte[] requestData)
|
||||
{
|
||||
FetchRequest request = (FetchRequest)Deserialize(requestData);
|
||||
|
||||
DataPortal portal = new DataPortal();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = portal.Fetch(request.ObjectType, request.Criteria, request.Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result = ex;
|
||||
}
|
||||
return Serialize(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="requestData">Byte stream containing <see cref="UpdateRequest" />.</param>
|
||||
/// <returns>Byte stream containing resulting object data.</returns>
|
||||
[WebMethod()]
|
||||
public byte[] Update(byte[] requestData)
|
||||
{
|
||||
UpdateRequest request = (UpdateRequest)Deserialize(requestData);
|
||||
|
||||
DataPortal portal = new DataPortal();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = portal.Update(request.Object, request.Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result = ex;
|
||||
}
|
||||
return Serialize(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="requestData">Byte stream containing <see cref="DeleteRequest" />.</param>
|
||||
/// <returns>Byte stream containing resulting object data.</returns>
|
||||
[WebMethod()]
|
||||
public byte[] Delete(byte[] requestData)
|
||||
{
|
||||
DeleteRequest request = (DeleteRequest)Deserialize(requestData);
|
||||
|
||||
DataPortal portal = new DataPortal();
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = portal.Delete(request.Criteria, request.Context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result = ex;
|
||||
}
|
||||
return Serialize(result);
|
||||
}
|
||||
|
||||
#region Helper functions
|
||||
|
||||
private static byte[] Serialize(object obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
using (MemoryStream buffer = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(buffer, obj);
|
||||
return buffer.ToArray();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object Deserialize(byte[] obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
using (MemoryStream buffer = new MemoryStream(obj))
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
return formatter.Deserialize(buffer);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Csla.Properties;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
internal static class MethodCaller
|
||||
{
|
||||
const BindingFlags allLevelFlags =
|
||||
BindingFlags.FlattenHierarchy |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic;
|
||||
|
||||
const BindingFlags oneLevelFlags =
|
||||
BindingFlags.DeclaredOnly |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the DataPortal_Create method for
|
||||
/// the specified business object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the business object.</param>
|
||||
/// <param name="criteria">Criteria parameter value.</param>
|
||||
/// <remarks>
|
||||
/// If the criteria parameter value is an integer, that is a special
|
||||
/// flag indicating that the parameter should be considered missing
|
||||
/// (not Nothing/null - just not there).
|
||||
/// </remarks>
|
||||
public static MethodInfo GetCreateMethod(Type objectType, object criteria)
|
||||
{
|
||||
MethodInfo method = null;
|
||||
if (criteria is int)
|
||||
{
|
||||
// an "Integer" criteria is a special flag indicating
|
||||
// that criteria is empty and should not be used
|
||||
method = MethodCaller.GetMethod(objectType, "DataPortal_Create");
|
||||
}
|
||||
else
|
||||
method = MethodCaller.GetMethod(objectType, "DataPortal_Create", criteria);
|
||||
return method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the DataPortal_Fetch method for
|
||||
/// the specified business object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the business object.</param>
|
||||
/// <param name="criteria">Criteria parameter value.</param>
|
||||
/// <remarks>
|
||||
/// If the criteria parameter value is an integer, that is a special
|
||||
/// flag indicating that the parameter should be considered missing
|
||||
/// (not Nothing/null - just not there).
|
||||
/// </remarks>
|
||||
public static MethodInfo GetFetchMethod(Type objectType, object criteria)
|
||||
{
|
||||
MethodInfo method = null;
|
||||
if (criteria is int)
|
||||
{
|
||||
// an "Integer" criteria is a special flag indicating
|
||||
// that criteria is empty and should not be used
|
||||
method = MethodCaller.GetMethod(objectType, "DataPortal_Fetch");
|
||||
}
|
||||
else
|
||||
method = MethodCaller.GetMethod(objectType, "DataPortal_Fetch", criteria);
|
||||
return method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to dynamically invoke a method
|
||||
/// if that method is implemented on the target object.
|
||||
/// </summary>
|
||||
public static object CallMethodIfImplemented(
|
||||
object obj, string method, params object[] parameters)
|
||||
{
|
||||
MethodInfo info = GetMethod(obj.GetType(), method, parameters);
|
||||
if (info != null)
|
||||
return CallMethod(obj, info, parameters);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to dynamically invoke a method,
|
||||
/// throwing an exception if it is not
|
||||
/// implemented on the target object.
|
||||
/// </summary>
|
||||
public static object CallMethod(
|
||||
object obj, string method, params object[] parameters)
|
||||
{
|
||||
MethodInfo info = GetMethod(obj.GetType(), method, parameters);
|
||||
if (info == null)
|
||||
throw new NotImplementedException(
|
||||
method + " " + Resources.MethodNotImplemented);
|
||||
return CallMethod(obj, info, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to dynamically invoke a method,
|
||||
/// throwing an exception if it is not
|
||||
/// implemented on the target object.
|
||||
/// </summary>
|
||||
public static object CallMethod(
|
||||
object obj, MethodInfo info, params object[] parameters)
|
||||
{
|
||||
// call a private method on the object
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = info.Invoke(obj, parameters);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Csla.Server.CallMethodException(
|
||||
info.Name + " " + Resources.MethodCallFailed, e.InnerException);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses reflection to locate a matching method
|
||||
/// on the target object.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethod(
|
||||
Type objectType, string method, params object[] parameters)
|
||||
{
|
||||
MethodInfo result = null;
|
||||
|
||||
// try to find a strongly typed match
|
||||
// put all param types into a list of Type
|
||||
List<Type> types = new List<Type>();
|
||||
foreach (object item in parameters)
|
||||
{
|
||||
if (item == null)
|
||||
types.Add(typeof(object));
|
||||
else
|
||||
types.Add(item.GetType());
|
||||
}
|
||||
|
||||
// first see if there's a matching method
|
||||
// where all params match types
|
||||
result = FindMethod(objectType, method, types.ToArray());
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
// no match found - so look for any method
|
||||
// with the right number of parameters
|
||||
result = FindMethod(objectType, method, parameters.Length);
|
||||
}
|
||||
|
||||
// no strongly typed match found, get default
|
||||
if (result == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = objectType.GetMethod(method, allLevelFlags);
|
||||
}
|
||||
catch (AmbiguousMatchException)
|
||||
{
|
||||
MethodInfo[] methods = objectType.GetMethods();
|
||||
foreach (MethodInfo m in methods)
|
||||
if (m.Name == method && m.GetParameters().Length == parameters.Length)
|
||||
{
|
||||
result = m;
|
||||
break;
|
||||
}
|
||||
if (result == null)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a business object type based on
|
||||
/// the supplied criteria object.
|
||||
/// </summary>
|
||||
public static Type GetObjectType(object criteria)
|
||||
{
|
||||
if (criteria.GetType().IsSubclassOf(typeof(CriteriaBase)))
|
||||
{
|
||||
// get the type of the actual business object
|
||||
// from CriteriaBase
|
||||
return ((CriteriaBase)criteria).ObjectType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the type of the actual business object
|
||||
// based on the nested class scheme in the book
|
||||
return criteria.GetType().DeclaringType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns information about the specified
|
||||
/// method, even if the parameter types are
|
||||
/// generic and are located in an abstract
|
||||
/// generic base class.
|
||||
/// </summary>
|
||||
public static MethodInfo FindMethod(Type objType, string method, Type[] types)
|
||||
{
|
||||
MethodInfo info = null;
|
||||
do
|
||||
{
|
||||
//find for a strongly typed match
|
||||
info = objType.GetMethod(method, oneLevelFlags, null, types, null);
|
||||
if (info != null)
|
||||
break; //match found
|
||||
|
||||
objType = objType.BaseType;
|
||||
} while (objType != null);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns information about the specified
|
||||
/// method, finding the method based purely
|
||||
/// on the method name and number of parameters.
|
||||
/// </summary>
|
||||
public static MethodInfo FindMethod(Type objType, string method, int parameterCount)
|
||||
{
|
||||
// walk up the inheritance hierarchy looking
|
||||
// for a method with the right number of
|
||||
// parameters
|
||||
MethodInfo result = null;
|
||||
Type currentType = objType;
|
||||
do
|
||||
{
|
||||
MethodInfo info = currentType.GetMethod(method, oneLevelFlags);
|
||||
if (info != null)
|
||||
{
|
||||
if (info.GetParameters().Length == parameterCount)
|
||||
{
|
||||
// got a match so use it
|
||||
result = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentType = currentType.BaseType;
|
||||
} while (currentType != null);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks a DataPortal_XYZ method to
|
||||
/// be run on the client even if the server-side
|
||||
/// DataPortal is configured for remote use.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class RunLocalAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// This exception is returned from the
|
||||
/// CallMethod method in the server-side DataPortal
|
||||
/// and contains the exception thrown by the
|
||||
/// underlying business object method that was
|
||||
/// being invoked.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
|
||||
[Serializable()]
|
||||
public class CallMethodException : Exception
|
||||
{
|
||||
private string _innerStackTrace;
|
||||
|
||||
/// <summary>
|
||||
/// Get the stack trace from the original
|
||||
/// exception.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
/// <returns></returns>
|
||||
/// <remarks></remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)")]
|
||||
public override string StackTrace
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}{1}{2}",
|
||||
_innerStackTrace, Environment.NewLine, base.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Message text describing the exception.</param>
|
||||
/// <param name="ex">Inner exception object.</param>
|
||||
public CallMethodException(string message, Exception ex)
|
||||
: base(message, ex)
|
||||
{
|
||||
_innerStackTrace = ex.StackTrace;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object for deserialization.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization info.</param>
|
||||
/// <param name="context">Serialiation context.</param>
|
||||
protected CallMethodException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
_innerStackTrace = info.GetString("_innerStackTrace");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the object.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialization info.</param>
|
||||
/// <param name="context">Serialization context.</param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("_innerStackTrace", _innerStackTrace);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,327 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Security.Principal;
|
||||
using System.Collections.Specialized;
|
||||
using Csla.Properties;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the server-side DataPortal
|
||||
/// message router as discussed
|
||||
/// in Chapter 4.
|
||||
/// </summary>
|
||||
public class DataPortal : IDataPortalServer
|
||||
{
|
||||
|
||||
#region Data Access
|
||||
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Create(
|
||||
Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetContext(context);
|
||||
|
||||
DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetCreateMethod(objectType, criteria);
|
||||
|
||||
IDataPortalServer portal;
|
||||
switch (TransactionalType(method))
|
||||
{
|
||||
case TransactionalTypes.EnterpriseServices:
|
||||
portal = new ServicedDataPortal();
|
||||
try
|
||||
{
|
||||
result = portal.Create(objectType, criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((ServicedDataPortal)portal).Dispose();
|
||||
}
|
||||
|
||||
break;
|
||||
case TransactionalTypes.TransactionScope:
|
||||
|
||||
portal = new TransactionalDataPortal();
|
||||
result = portal.Create(objectType, criteria, context);
|
||||
|
||||
break;
|
||||
default:
|
||||
portal = new SimpleDataPortal();
|
||||
result = portal.Create(objectType, criteria, context);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ClearContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetContext(context);
|
||||
|
||||
DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetFetchMethod(objectType, criteria);
|
||||
|
||||
IDataPortalServer portal;
|
||||
switch (TransactionalType(method))
|
||||
{
|
||||
case TransactionalTypes.EnterpriseServices:
|
||||
portal = new ServicedDataPortal();
|
||||
try
|
||||
{
|
||||
result = portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((ServicedDataPortal)portal).Dispose();
|
||||
}
|
||||
break;
|
||||
case TransactionalTypes.TransactionScope:
|
||||
portal = new TransactionalDataPortal();
|
||||
result = portal.Fetch(objectType, criteria, context);
|
||||
break;
|
||||
default:
|
||||
portal = new SimpleDataPortal();
|
||||
result = portal.Fetch(objectType, criteria, context);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ClearContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetContext(context);
|
||||
|
||||
DataPortalResult result;
|
||||
|
||||
MethodInfo method;
|
||||
string methodName;
|
||||
if (obj is CommandBase)
|
||||
methodName = "DataPortal_Execute";
|
||||
else if (obj is Core.BusinessBase)
|
||||
{
|
||||
Core.BusinessBase tmp = (Core.BusinessBase)obj;
|
||||
if (tmp.IsDeleted)
|
||||
methodName = "DataPortal_DeleteSelf";
|
||||
else
|
||||
if (tmp.IsNew)
|
||||
methodName = "DataPortal_Insert";
|
||||
else
|
||||
methodName = "DataPortal_Update";
|
||||
}
|
||||
else
|
||||
methodName = "DataPortal_Update";
|
||||
|
||||
method = MethodCaller.GetMethod(obj.GetType(), methodName);
|
||||
|
||||
IDataPortalServer portal;
|
||||
switch (TransactionalType(method))
|
||||
{
|
||||
case TransactionalTypes.EnterpriseServices:
|
||||
portal = new ServicedDataPortal();
|
||||
try
|
||||
{
|
||||
result = portal.Update(obj, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((ServicedDataPortal)portal).Dispose();
|
||||
}
|
||||
break;
|
||||
case TransactionalTypes.TransactionScope:
|
||||
portal = new TransactionalDataPortal();
|
||||
result = portal.Update(obj, context);
|
||||
break;
|
||||
default:
|
||||
portal = new SimpleDataPortal();
|
||||
result = portal.Update(obj, context);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ClearContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetContext(context);
|
||||
|
||||
DataPortalResult result;
|
||||
|
||||
MethodInfo method = MethodCaller.GetMethod(
|
||||
MethodCaller.GetObjectType(criteria), "DataPortal_Delete", criteria);
|
||||
|
||||
IDataPortalServer portal;
|
||||
switch (TransactionalType(method))
|
||||
{
|
||||
case TransactionalTypes.EnterpriseServices:
|
||||
portal = new ServicedDataPortal();
|
||||
try
|
||||
{
|
||||
result = portal.Delete(criteria, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((ServicedDataPortal)portal).Dispose();
|
||||
}
|
||||
break;
|
||||
case TransactionalTypes.TransactionScope:
|
||||
portal = new TransactionalDataPortal();
|
||||
result = portal.Delete(criteria, context);
|
||||
break;
|
||||
default:
|
||||
portal = new SimpleDataPortal();
|
||||
result = portal.Delete(criteria, context);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ClearContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Context
|
||||
|
||||
private static void SetContext(DataPortalContext context)
|
||||
{
|
||||
// if the dataportal is not remote then
|
||||
// do nothing
|
||||
if (!context.IsRemotePortal) return;
|
||||
|
||||
// set the context value so everyone knows the
|
||||
// code is running on the server
|
||||
ApplicationContext.SetExecutionLocation(ApplicationContext.ExecutionLocations.Server);
|
||||
|
||||
// set the app context to the value we got from the
|
||||
// client
|
||||
ApplicationContext.SetContext(context.ClientContext, context.GlobalContext);
|
||||
|
||||
// set the thread's culture to match the client
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture =
|
||||
new System.Globalization.CultureInfo(context.ClientCulture);
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture =
|
||||
new System.Globalization.CultureInfo(context.ClientUICulture);
|
||||
|
||||
if (ApplicationContext.AuthenticationType == "Windows")
|
||||
{
|
||||
// When using integrated security, Principal must be null
|
||||
if (context.Principal == null)
|
||||
{
|
||||
// Set .NET to use integrated security
|
||||
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Security.SecurityException(Resources.NoPrincipalAllowedException);
|
||||
}
|
||||
}
|
||||
// We expect the Principal to be of the type BusinesPrincipal
|
||||
if (context.Principal != null)
|
||||
{
|
||||
if (context.Principal is Security.BusinessPrincipalBase)
|
||||
ApplicationContext.User = context.Principal;
|
||||
else
|
||||
throw new System.Security.SecurityException(
|
||||
Resources.BusinessPrincipalException + " " +
|
||||
((object)context.Principal).ToString());
|
||||
}
|
||||
else
|
||||
throw new System.Security.SecurityException(
|
||||
Resources.BusinessPrincipalException + " Nothing");
|
||||
}
|
||||
|
||||
private static void ClearContext(DataPortalContext context)
|
||||
{
|
||||
// if the dataportal is not remote then
|
||||
// do nothing
|
||||
if (!context.IsRemotePortal) return;
|
||||
ApplicationContext.Clear();
|
||||
if (ApplicationContext.AuthenticationType != "Windows")
|
||||
ApplicationContext.User = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper methods
|
||||
|
||||
private static bool IsTransactionalMethod(MethodInfo method)
|
||||
{
|
||||
return Attribute.IsDefined(method, typeof(TransactionalAttribute));
|
||||
}
|
||||
|
||||
private static TransactionalTypes TransactionalType(MethodInfo method)
|
||||
{
|
||||
TransactionalTypes result;
|
||||
if (IsTransactionalMethod(method))
|
||||
{
|
||||
TransactionalAttribute attrib =
|
||||
(TransactionalAttribute)Attribute.GetCustomAttribute(
|
||||
method, typeof(TransactionalAttribute));
|
||||
result = attrib.TransactionType;
|
||||
}
|
||||
else
|
||||
result = TransactionalTypes.Manual;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides consistent context information between the client
|
||||
/// and server DataPortal objects.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class DataPortalContext
|
||||
{
|
||||
private IPrincipal _principal;
|
||||
private bool _remotePortal;
|
||||
private string _clientCulture;
|
||||
private string _clientUICulture;
|
||||
private HybridDictionary _clientContext;
|
||||
private HybridDictionary _globalContext;
|
||||
|
||||
/// <summary>
|
||||
/// The current principal object
|
||||
/// if CSLA security is being used.
|
||||
/// </summary>
|
||||
public IPrincipal Principal
|
||||
{
|
||||
get { return _principal; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the
|
||||
/// server-side DataPortal is running
|
||||
/// on a remote server via remoting.
|
||||
/// </summary>
|
||||
public bool IsRemotePortal
|
||||
{
|
||||
get { return _remotePortal; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The culture setting on the client
|
||||
/// workstation.
|
||||
/// </summary>
|
||||
public string ClientCulture
|
||||
{
|
||||
get { return _clientCulture; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The culture setting on the client
|
||||
/// workstation.
|
||||
/// </summary>
|
||||
public string ClientUICulture
|
||||
{
|
||||
get { return _clientUICulture; }
|
||||
}
|
||||
internal HybridDictionary ClientContext
|
||||
{
|
||||
get { return _clientContext; }
|
||||
}
|
||||
|
||||
internal HybridDictionary GlobalContext
|
||||
{
|
||||
get { return _globalContext; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new DataPortalContext object.
|
||||
/// </summary>
|
||||
/// <param name="principal">The current Principal object.</param>
|
||||
/// <param name="isRemotePortal">Indicates whether the DataPortal is remote.</param>
|
||||
public DataPortalContext(IPrincipal principal, bool isRemotePortal)
|
||||
{
|
||||
if (isRemotePortal)
|
||||
{
|
||||
_principal = principal;
|
||||
_remotePortal = isRemotePortal;
|
||||
_clientCulture =
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture.Name;
|
||||
_clientUICulture =
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
|
||||
_clientContext = Csla.ApplicationContext.GetClientContext();
|
||||
_globalContext = Csla.ApplicationContext.GetGlobalContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// This exception is returned from the
|
||||
/// server-side DataPortal and contains the exception
|
||||
/// and context data from the server.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
|
||||
[Serializable()]
|
||||
public class DataPortalException : Exception
|
||||
{
|
||||
private DataPortalResult _result;
|
||||
private string _innerStackTrace;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the DataPortalResult object from the server.
|
||||
/// </summary>
|
||||
public DataPortalResult Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the server-side stack trace from the
|
||||
/// original exception.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)")]
|
||||
public override string StackTrace
|
||||
{
|
||||
get { return String.Format("{0}{1}{2}",
|
||||
_innerStackTrace, Environment.NewLine, base.StackTrace); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="message">Text describing the exception.</param>
|
||||
/// <param name="ex">Inner exception.</param>
|
||||
/// <param name="result">The data portal result object.</param>
|
||||
public DataPortalException(
|
||||
string message, Exception ex, DataPortalResult result)
|
||||
: base(message, ex)
|
||||
{
|
||||
_innerStackTrace = ex.StackTrace;
|
||||
_result = result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object for serialization.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialiation info object.</param>
|
||||
/// <param name="context">Serialization context object.</param>
|
||||
protected DataPortalException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
_result = (DataPortalResult)info.GetValue(
|
||||
"_result", typeof(DataPortalResult));
|
||||
_innerStackTrace = info.GetString("_innerStackTrace");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the object.
|
||||
/// </summary>
|
||||
/// <param name="info">Serialiation info object.</param>
|
||||
/// <param name="context">Serialization context object.</param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
|
||||
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
|
||||
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
|
||||
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("_result", _result);
|
||||
info.AddValue("_innerStackTrace", _innerStackTrace);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns data from the server-side DataPortal to the
|
||||
/// client-side DataPortal. Intended for internal CSLA .NET
|
||||
/// use only.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class DataPortalResult
|
||||
{
|
||||
private object _returnObject;
|
||||
private HybridDictionary _globalContext;
|
||||
|
||||
/// <summary>
|
||||
/// The business object being returned from
|
||||
/// the server.
|
||||
/// </summary>
|
||||
public object ReturnObject
|
||||
{
|
||||
get { return _returnObject; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The global context being returned from
|
||||
/// the server.
|
||||
/// </summary>
|
||||
public HybridDictionary GlobalContext
|
||||
{
|
||||
get { return _globalContext; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
public DataPortalResult()
|
||||
{
|
||||
_globalContext = ApplicationContext.GetGlobalContext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the object.
|
||||
/// </summary>
|
||||
/// <param name="returnObject">Object to return as part
|
||||
/// of the result.</param>
|
||||
public DataPortalResult(object returnObject)
|
||||
{
|
||||
_returnObject = returnObject;
|
||||
_globalContext = ApplicationContext.GetGlobalContext();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface implemented by server-side data portal
|
||||
/// components.
|
||||
/// </summary>
|
||||
public interface IDataPortalServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
DataPortalResult Create(Type objectType, object criteria, DataPortalContext context);
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context);
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
DataPortalResult Update(object obj, DataPortalContext context);
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
DataPortalResult Delete(object criteria, DataPortalContext context);
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.EnterpriseServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the server-side Serviced
|
||||
/// DataPortal described in Chapter 4.
|
||||
/// </summary>
|
||||
[Transaction(TransactionOption.Required)]
|
||||
[EventTrackingEnabled(true)]
|
||||
[ComVisible(true)]
|
||||
public class ServicedDataPortal : ServicedComponent, IDataPortalServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps a Create call in a ServicedComponent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a COM+ transaction
|
||||
/// to provide transactional support.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">A <see cref="Type">Type</see> object
|
||||
/// indicating the type of business object to be created.</param>
|
||||
/// <param name="criteria">A custom criteria object providing any
|
||||
/// extra information that may be required to properly create
|
||||
/// the object.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
/// <returns>A populated business object.</returns>
|
||||
[AutoComplete(true)]
|
||||
public DataPortalResult Create(
|
||||
Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
return portal.Create(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a Fetch call in a ServicedComponent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a COM+ transaction
|
||||
/// to provide transactional support.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <param name="context">Object containing context data from client.</param>
|
||||
/// <returns>A populated business object.</returns>
|
||||
[AutoComplete(true)]
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
return portal.Fetch(objectType, criteria, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an Update call in a ServicedComponent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a COM+ transaction
|
||||
/// to provide transactional support.
|
||||
/// </remarks>
|
||||
/// <param name="obj">A reference to the object being updated.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
/// <returns>A reference to the newly updated object.</returns>
|
||||
[AutoComplete(true)]
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
return portal.Update(obj, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a Delete call in a ServicedComponent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a COM+ transaction
|
||||
/// to provide transactional support.
|
||||
/// </remarks>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
[AutoComplete(true)]
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
return portal.Delete(criteria, context);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,317 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Security.Principal;
|
||||
using System.Collections.Specialized;
|
||||
using Csla.Properties;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the server-side DataPortal as discussed
|
||||
/// in Chapter 4.
|
||||
/// </summary>
|
||||
public class SimpleDataPortal : IDataPortalServer
|
||||
{
|
||||
|
||||
#region Data Access
|
||||
|
||||
/// <summary>
|
||||
/// Create a new business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to create.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.Server.DataPortalException.#ctor(System.String,System.Exception,Csla.Server.DataPortalResult)")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public DataPortalResult Create(
|
||||
Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
object obj = null;
|
||||
|
||||
try
|
||||
{
|
||||
// create an instance of the business object.
|
||||
obj = Activator.CreateInstance(objectType, true);
|
||||
|
||||
// tell the business object we're about to make a DataPortal_xyz call
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvoke", new DataPortalEventArgs(context));
|
||||
|
||||
// tell the business object to create its data
|
||||
MethodInfo method = MethodCaller.GetCreateMethod(objectType, criteria);
|
||||
if (criteria is int)
|
||||
MethodCaller.CallMethod(obj, method);
|
||||
else
|
||||
MethodCaller.CallMethod(obj, method, criteria);
|
||||
|
||||
// mark the object as new
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "MarkNew");
|
||||
|
||||
// tell the business object the DataPortal_xyz call is complete
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvokeComplete",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
// return the populated business object as a result
|
||||
return new DataPortalResult(obj);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
// tell the business object there was an exception
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalException",
|
||||
new DataPortalEventArgs(context), ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore exceptions from the exception handler
|
||||
}
|
||||
throw new DataPortalException(
|
||||
"DataPortal.Create " + Resources.FailedOnServer,
|
||||
ex, new DataPortalResult(obj));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing business object.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.Server.DataPortalException.#ctor(System.String,System.Exception,Csla.Server.DataPortalResult)")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
// create an instance of the business object.
|
||||
obj = Activator.CreateInstance(objectType, true);
|
||||
|
||||
// tell the business object we're about to make a DataPortal_xyz call
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvoke",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
// tell the business object to fetch its data
|
||||
MethodInfo method = MethodCaller.GetFetchMethod(objectType, criteria);
|
||||
if (criteria is int)
|
||||
MethodCaller.CallMethod(obj, method);
|
||||
else
|
||||
MethodCaller.CallMethod(obj, method, criteria);
|
||||
|
||||
// mark the object as old
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "MarkOld");
|
||||
|
||||
// tell the business object the DataPortal_xyz call is complete
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvokeComplete",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
// return the populated business object as a result
|
||||
return new DataPortalResult(obj);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
// tell the business object there was an exception
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalException",
|
||||
new DataPortalEventArgs(context), ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore exceptions from the exception handler
|
||||
}
|
||||
throw new DataPortalException(
|
||||
"DataPortal.Fetch " + Resources.FailedOnServer,
|
||||
ex, new DataPortalResult(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a business object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Business object to update.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.Server.DataPortalException.#ctor(System.String,System.Exception,Csla.Server.DataPortalResult)")]
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
// tell the business object we're about to make a DataPortal_xyz call
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvoke",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
// tell the business object to update itself
|
||||
if (obj is Core.BusinessBase)
|
||||
{
|
||||
Core.BusinessBase busObj = (Core.BusinessBase)obj;
|
||||
if (busObj.IsDeleted)
|
||||
{
|
||||
if (!busObj.IsNew)
|
||||
{
|
||||
// tell the object to delete itself
|
||||
MethodCaller.CallMethod(
|
||||
busObj, "DataPortal_DeleteSelf");
|
||||
}
|
||||
// mark the object as new
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
busObj, "MarkNew");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (busObj.IsNew)
|
||||
{
|
||||
// tell the object to insert itself
|
||||
MethodCaller.CallMethod(
|
||||
busObj, "DataPortal_Insert");
|
||||
}
|
||||
else
|
||||
{
|
||||
// tell the object to update itself
|
||||
MethodCaller.CallMethod(
|
||||
busObj, "DataPortal_Update");
|
||||
}
|
||||
// mark the object as old
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
busObj, "MarkOld");
|
||||
}
|
||||
}
|
||||
else if (obj is CommandBase)
|
||||
{
|
||||
// tell the object to update itself
|
||||
MethodCaller.CallMethod(
|
||||
obj, "DataPortal_Execute");
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is an updatable collection or some other
|
||||
// non-BusinessBase type of object
|
||||
// tell the object to update itself
|
||||
MethodCaller.CallMethod(
|
||||
obj, "DataPortal_Update");
|
||||
// mark the object as old
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "MarkOld");
|
||||
}
|
||||
|
||||
// tell the business object the DataPortal_xyz is complete
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvokeComplete",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
return new DataPortalResult(obj);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
// tell the business object there was an exception
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalException",
|
||||
new DataPortalEventArgs(context), ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore exceptions from the exception handler
|
||||
}
|
||||
throw new DataPortalException(
|
||||
"DataPortal.Update " + Resources.FailedOnServer,
|
||||
ex, new DataPortalResult(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a business object.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Criteria object describing business object.</param>
|
||||
/// <param name="context">
|
||||
/// <see cref="Server.DataPortalContext" /> object passed to the server.
|
||||
/// </param>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "Csla.Server.DataPortalException.#ctor(System.String,System.Exception,Csla.Server.DataPortalResult)")]
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
// create an instance of the business objet
|
||||
obj = CreateBusinessObject(criteria);
|
||||
|
||||
// tell the business object we're about to make a DataPortal_xyz call
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvoke",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
// tell the business object to delete itself
|
||||
MethodCaller.CallMethod(
|
||||
obj, "DataPortal_Delete", criteria);
|
||||
|
||||
// tell the business object the DataPortal_xyz call is complete
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalInvokeComplete",
|
||||
new DataPortalEventArgs(context));
|
||||
|
||||
return new DataPortalResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
// tell the business object there was an exception
|
||||
MethodCaller.CallMethodIfImplemented(
|
||||
obj, "DataPortal_OnDataPortalException",
|
||||
new DataPortalEventArgs(context), ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore exceptions from the exception handler
|
||||
}
|
||||
throw new DataPortalException(
|
||||
"DataPortal.Delete " + Resources.FailedOnServer,
|
||||
ex, new DataPortalResult());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Creating the business object
|
||||
|
||||
private static object CreateBusinessObject(object criteria)
|
||||
{
|
||||
Type businessType;
|
||||
if (criteria.GetType().IsSubclassOf(typeof(CriteriaBase)))
|
||||
{
|
||||
// get the type of the actual business object
|
||||
// from CriteriaBase
|
||||
businessType = ((CriteriaBase)criteria).ObjectType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the type of the actual business object
|
||||
// based on the nested class scheme in the book
|
||||
businessType = criteria.GetType().DeclaringType;
|
||||
}
|
||||
|
||||
// create an instance of the business object
|
||||
return Activator.CreateInstance(businessType, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Transactions;
|
||||
|
||||
namespace Csla.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the server-side Serviced
|
||||
/// DataPortal described in Chapter 4.
|
||||
/// </summary>
|
||||
public class TransactionalDataPortal : IDataPortalServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps a Create call in a TransactionScope
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a
|
||||
/// <see cref="TransactionScope">TransactionScope</see>
|
||||
/// to provide transactional support via
|
||||
/// System.Transactions.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">A <see cref="Type">Type</see> object
|
||||
/// indicating the type of business object to be created.</param>
|
||||
/// <param name="criteria">A custom criteria object providing any
|
||||
/// extra information that may be required to properly create
|
||||
/// the object.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
/// <returns>A populated business object.</returns>
|
||||
public DataPortalResult Create(
|
||||
System.Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
DataPortalResult result;
|
||||
using (TransactionScope tr = new TransactionScope())
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
result = portal.Create(objectType, criteria, context);
|
||||
tr.Complete();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the client-side DataProtal to retrieve an object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a
|
||||
/// <see cref="TransactionScope">TransactionScope</see>
|
||||
/// to provide transactional support via
|
||||
/// System.Transactions.
|
||||
/// </remarks>
|
||||
/// <param name="objectType">Type of business object to retrieve.</param>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <param name="context">Object containing context data from client.</param>
|
||||
/// <returns>A populated business object.</returns>
|
||||
public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
|
||||
{
|
||||
DataPortalResult result;
|
||||
using (TransactionScope tr = new TransactionScope())
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
result = portal.Fetch(objectType, criteria, context);
|
||||
tr.Complete();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the client-side DataPortal to update an object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a
|
||||
/// <see cref="TransactionScope">TransactionScope</see>
|
||||
/// to provide transactional support via
|
||||
/// System.Transactions.
|
||||
/// </remarks>
|
||||
/// <param name="obj">A reference to the object being updated.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
/// <returns>A reference to the newly updated object.</returns>
|
||||
public DataPortalResult Update(object obj, DataPortalContext context)
|
||||
{
|
||||
DataPortalResult result;
|
||||
using (TransactionScope tr = new TransactionScope())
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
result = portal.Update(obj, context);
|
||||
tr.Complete();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the client-side DataPortal to delete an object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method delegates to
|
||||
/// <see cref="SimpleDataPortal">SimpleDataPortal</see>
|
||||
/// but wraps that call within a
|
||||
/// <see cref="TransactionScope">TransactionScope</see>
|
||||
/// to provide transactional support via
|
||||
/// System.Transactions.
|
||||
/// </remarks>
|
||||
/// <param name="criteria">Object-specific criteria.</param>
|
||||
/// <param name="context">Context data from the client.</param>
|
||||
public DataPortalResult Delete(object criteria, DataPortalContext context)
|
||||
{
|
||||
DataPortalResult result;
|
||||
using (TransactionScope tr = new TransactionScope())
|
||||
{
|
||||
SimpleDataPortal portal = new SimpleDataPortal();
|
||||
result = portal.Delete(criteria, context);
|
||||
tr.Complete();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
|
||||
namespace Csla
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks a DataPortal_XYZ method to run within
|
||||
/// the specified transactional context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Each business object method may be marked with this attribute
|
||||
/// to indicate which type of transactional technology should
|
||||
/// be used by the server-side DataPortal. The possible options
|
||||
/// are listed in the
|
||||
/// <see cref="TransactionalTypes">TransactionalTypes</see> enum.
|
||||
/// </para><para>
|
||||
/// If the Transactional attribute is not applied to a
|
||||
/// DataPortal_XYZ method then the
|
||||
/// <see cref="TransactionalTypes.Manual">Manual</see> option
|
||||
/// is assumed.
|
||||
/// </para><para>
|
||||
/// If the Transactional attribute is applied with no explicit
|
||||
/// choice for transactionType then the
|
||||
/// <see cref="TransactionalTypes.EnterpriseServices">EnterpriseServices</see>
|
||||
/// option is assumed.
|
||||
/// </para><para>
|
||||
/// Both the EnterpriseServices and TransactionScope options provide
|
||||
/// 2-phase distributed transactional support.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class TransactionalAttribute : Attribute
|
||||
{
|
||||
private TransactionalTypes _type;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a method to run within a COM+
|
||||
/// transactional context.
|
||||
/// </summary>
|
||||
public TransactionalAttribute()
|
||||
{
|
||||
_type = TransactionalTypes.EnterpriseServices;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks a method to run within the specified
|
||||
/// type of transactional context.
|
||||
/// </summary>
|
||||
/// <param name="transactionType">
|
||||
/// Specifies the transactional context within which the
|
||||
/// method should run.</param>
|
||||
public TransactionalAttribute(TransactionalTypes transactionType)
|
||||
{
|
||||
_type = transactionType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of transaction requested by the
|
||||
/// business object method.
|
||||
/// </summary>
|
||||
public TransactionalTypes TransactionType
|
||||
{
|
||||
get { return _type; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
namespace Csla
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Provides a list of possible transactional
|
||||
/// technologies to be used by the server-side
|
||||
/// DataPortal.
|
||||
/// </summary>
|
||||
public enum TransactionalTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Causes the server-side DataPortal to
|
||||
/// use Enterprise Services (COM+) transactions.
|
||||
/// </summary>
|
||||
EnterpriseServices,
|
||||
/// <summary>
|
||||
/// Causes the server-side DataPortal to
|
||||
/// use System.Transactions TransactionScope
|
||||
/// style transactions.
|
||||
/// </summary>
|
||||
TransactionScope,
|
||||
/// <summary>
|
||||
/// Causes the server-side DataPortal to
|
||||
/// use no explicit transactional technology.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This option allows the business developer to
|
||||
/// implement their own transactions. Common options
|
||||
/// include ADO.NET transactions and System.Transactions
|
||||
/// TransactionScope.
|
||||
/// </remarks>
|
||||
Manual
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user