Commit for development environment setup

This commit is contained in:
2023-06-19 16:12:33 -04:00
parent be72063a3c
commit bbce2ad0a6
2209 changed files with 1171775 additions and 625 deletions

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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; }
}
}
}

View File

@@ -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;}
}
}

View File

@@ -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; }
}
}
}

View File

@@ -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; }
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
{
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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; }
}
}
}

View File

@@ -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
}
}