Hi,

    I don't know on what list I should post this message. If this is not the right 
list, please excuse me.
    This is how I'm trying to use DTOs to transfer data between layers in a 
distributed system and I'm sure there are a lot of mistakes in it. Any ideas about it 
are very welcomed. (The critical ones are too welcomed.)

    The BusinessFacade contains only stateful components. The most important are:
1) AppEntryComponent. It lazily creates one instance of the other stateful components 
in the BusinessFacade and keeps references to them. It's methods are basically 
GetSecurityComponent, GetReadableCarDTOFactory, GetUpdatableCarDTOFactory.
2) SecurityComponent. This components holds user information and sensitive data, such 
as the user's credentials.
3) ReadableCarDTOFactory : IReadableCarDTOFactory
4) UpdatableCarDTOFactory : IUpdatableCarDTOFactory

    The domain objects are created using data access components in the Data Access 
Layer. When ObjectSpaces is final, I'll probably use that framework for domain objects.
    The domain data transfer objects implement syntactic validation in the writable 
properties. That means syntactic validation occurs on the client side and on the 
server side in the Data Access Layer. Semantic/business validation occurs on the 
server side in the Business Rules Layer.

    All the components are given a reference to the AppEntryComponent that created 
them. That is because the stateful components need the other stateful components for 
processing.

    The DTO factory interfaces are implemented by Business Facade stateful components, 
as well as by transactional components in the Data Access Layer and the updatable 
interfaces are also implemented by transactional components in the Business Rules 
Layer.



namespace SystemFrameworkProjects;

public interface IReadableCarDTOFactory
{
    // mutable domain data transfer objects
    CarDTO FindCarDTO(CarPK aCarPK);
    ManufacturerDTO GetManufacturerDTOForCar(CarPK aCarPK);

    // immutable custom data transfer objects
    CarEngineDTO GetCarEngineDTO(CarPK aCarPK);

    // immutable aggregate data transfer objects
    CarAndManufacturerDTO GetCarAndManufacturerDTO(CarPK aCarPK);
}

public interface IUpdatableCarDTOFactory : IReadableCarDTOFactory
{
    void UpdateCar(CarDTO aCarDTO);
    void UpdateManufacturerForCar(CarPK aCarPK, ManufacturerDTO aManufacturerDTO);
}






namespace BusinessFacade;

// non-transactional, non-JITA
public class CarDTOFactory : ServicedComponent, IUpdatableCarDTOFactory // , 
IReadableCarDTOFactory
{
    private SecurityComponent sc;
    private DataAccessLayer.ReadableCarDTOFactory readableCarDTOFactory; // JITA, no 
need to explicitly dispose of
    private BusinessRulesLayer.UpdatableCarDTOFactory updatableCarDTOFactory; // JITA, 
no need to explicitly dispose of

    public void SetAppEntryComponent(AppEntryComponent comp)
    {
        // keep references to what we need
        sc = comp.GetSecurityComponent();
        readableCarDTOFactory= new BusinessRulesLayer.ReadableCarDTOFactory();
        updatableCarDTOFactory = new BusinessRulesLayer.UpdatableCarDTOFactory();
    }

    public CarDTO IReadableCarDTOFactory.FindCarDTO(CarPK aCarPK)
    {
        if (sc == null)
            throw new InvalidStateException("please call SetAppEntryComponent first");
        sc.CheckFindCarPermission(aCarPK); // throws SecurityException
        return readableCarDTOFactory.FindCarDTO(aCarPK);
    }

    public void IUpdatableCarDTOFactory.UpdateCar(CarDTO aCarDTO)
    {
        if (sc == null)
            throw new InvalidStateException("please call SetAppEntryComponent first");
        sc.CheckUpdateCarPermission(aCarDTO); // throws SecurityException
        updatableCarDTOFactory.UpdateCar(aCarDTO);
    }
}

    The are 2 kinds of data access components in the DAL:
1) serviced components with Supported Transaction semantics for read-only data access
2) serviced components with Required Transaction semantics for updates

Example:



namespace DataAccessLayer;

[Transaction(TransactionOption.Supported)]
public class ReadableCarDAO : ServicedComponent, IReadableCarDTOFactory
{
    ...
}

[Transaction(TransactionOption.Required)]
public class UpdatableCarDAO : ReadableCarDAO, IUpdatableCarDTOFactory
{
    ...
}








namespace BusinessRulesLayer;

[Transaction(TransactionOption.Required)]
public class UpdatableCarDAO : ServicedComponent, IUpdatableCarDTOFactory
{
    private DataAccessLayer.UpdatableCarDAO dao; // JITA, no need to be explicitly 
disposed of

    public UpdatableCarDAO()
    {
        dao = new DataAccessLayer.UpdatableCarDAO();
    }

    [AutoComplete]
    public void IUpdatableCarDTOFactory.UpdateCar(CarDTO aCarDTO)
    {
        CarDTO oldCar = dao.FindCar(aCarDTO.PrimaryKey);
        if (oldCar.WheelsCount != aCarDTO.WheelsCount) // enforce business rule
            throw new WheelsCountMismatch();
        else
            dao.UpdateCar(aCarDTO);
    }
}



    The DAO components are coarse-grained and work only with domain data transfer 
objects (similar to the entity beans in EJB 1.x based applications). They actually 
implement something similar to the home interfaces in EJB. (It is possible simulate 
the EJB local interfaces by optionally making the DAO components to be library 
activated and making the fine-grained methods not deactivate the context at return but 
I don't know if this approach is feasable with COM+.)
    The DAO components are compile-time dependent only on domain data transfer 
objects, but they do not depend on custom data trasfer objects.

    The system will contain other business rules components, not closely related to 
the DTO concept.

    By this design I want to acomplish 3 things:
1) The client must not pass the username/password to the server at every call.
2) We can easily migrate domain objects from DAO to Object Spaces when it is final.
3) I keep most of the components stateless. The Business Facade Layer does not imply 
so many scalability concerns like it is the Business Rules Layer or the Data Access 
Layer, so the only layer of stateful components is the business facade.

    Because of the DCOM "pinging" mechanism, in case the client crashes, the business 
facade stateful components are automaticaly disposed of.

    Is this design acceptable in the .NET/COM+ world ?


TIA,
Daniel Aioanei

You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced 
DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to