Структура проекта для приложения EF/Silverlight

В настоящее время я работаю над поиском хорошей структуры проекта для трехуровневого решения, чтобы избежать ненужной работы в новом проекте.

Проект будет состоять из основного продукта, который

  • модельный проект, который содержит первые модели кода EF
  • проект, который имеет бизнес-логику и коммуникационную логику на сервере
  • проект репозитория на клиенте
  • проект silverlight с представлениями и моделями представлений (здесь хотелось бы использовать caliburn.micro)

Проблема сейчас в том, что у заказчика могут быть особые требования, которые могут привести к изменениям во всех вышеперечисленных проектах. Поэтому я подумал, что могу просто использовать базовую структуру и создать такую ​​же структуру для клиента. Если бы изменений не было, у меня были бы просто пустые классы, которые просто расширяли бы базовый класс и ничего не добавляли.

Что приводит меня к следующим проблемам:

  • Является ли проблемой в Entity Framework (сначала код) иметь базовые классы в одном проекте (который уже полностью функционален) и иметь другой проект, который может расширить классы модели новым полем?
  • Является ли проблема в XAML изменением пользовательского элемента управления? Например, если у меня есть пользовательский элемент управления, состоящий из пяти текстовых полей в моем ядре, и я хочу изменить второе поле на переключатель, но ничего больше.

Я также приму изменения в структуре проекта, если есть лучший способ обработки изменений, специфичных для клиента.

Редактировать: я, вероятно, буду использовать следующий подход для решения проблемы.

Структура сущности:

С кодом сначала кажется возможным, чтобы один модельный проект расширял другой проект. Это означает, что я мог бы написать что-то вроде:

public class CoreAddress{
  [Key]
  public int AdrId{get; set;}
  public string Street {get;set;}
}

public class CustomerAddress : CoreAddress{
  public string StreetNumber {get; set;}
}

Единственное, что нужно для того, чтобы это работало, — это строка внутри DbContext:

(this as IObjectContextAdapter).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(<entity from other assembly>).Assembly);

XAML

Чтобы получить подобное поведение в XAML, мне пришлось использовать Caliburn.Micro (в сочетании с MEF), что очень помогло.

Я бы создал элементы управления UserControl, включающие элементы ContentControl, которые динамически извлекаются с помощью MEF. Это означает, что у меня снова есть основной проект со всеми представлениями и ViewModels. Если мне нужно где-то обменять специальный элемент управления для клиента, я меняю элемент управления на ContentControl и создаю для него базовое представление и ViewModel (то же самое, что было до запроса на изменение). Эта ViewModel для ContentControl аннотируется интерфейсом экспорта и ExportMetadata для установки приоритета 1. Теперь я создаю другой проект с другим UserControl, который имеет какой-то другой элемент управления вместо основного элемента управления, и снова аннотирую его как экспорт с тем же интерфейсом, но установите мой приоритет выше, и поэтому будет загружен пользовательский элемент управления.

Короткий пример для этого:

Основной пользовательский элемент управления и модель просмотра:

<UserControl x:Class="SilverlightApplication5.TestView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <ContentControl x:Name="Item"/>
            <TextBox x:Name="TextItem" Text="asdf"/>
        </StackPanel>

    </Grid>
</UserControl>

public class TestViewModel : Screen
    {
        private object viewModel;
        private Lazy<IMyViewModel, IPluginMetadata>[] _orderEditorFactory;

        [ImportMany(typeof(IMyViewModel), AllowRecomposition = true)]
        public Lazy<IMyViewModel, IPluginMetadata>[] OrderEditorFactory
        {
            get { return _orderEditorFactory; }
            set
            {
                _orderEditorFactory = value;
                Item = _orderEditorFactory.OrderByDescending(lazy => lazy.Metadata.Priority).First().Value;

            }
        }
    private object _item;

        public object Item
        {
            get { return _item; }
            set
            {
                _item = value;
                NotifyOfPropertyChange(() => Item);
            }
        }
    }

Основной контроль:

<UserControl x:Class="SilverlightClassLibrary2.MainControlView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <StackPanel>
        <TextBlock x:Name="Test" Text="Text from Core control"/>
    </StackPanel>
</UserControl>

[Export(typeof (IMyViewModel))]
[ExportMetadata("Name", "Pluginc")]
[ExportMetadata("Priority", 30)]
public class MainControlViewModel : Screen, IHarnessAware, IMyViewModel
{

}

Индивидуальный контроль клиента:

<UserControl x:Class="SilverlightClassLibrary1.CustomView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <RadioButton x:Name="Test" Content="{Binding Path=Test}"/>
    </Grid>
</UserControl>

[Export(typeof(IMyViewModel))]
[ExportMetadata("Name", "Plugind")]
[ExportMetadata("Priority", 2)]
public class CustomViewModel : MainControlViewModel, IHarnessAware, IMyViewModel
{
}

Интерфейс экспорта:

public interface IMyViewModel
{

}

Интерфейс экспорта метаданных:

   public interface 
        IPluginMetadata
    {
        string Name { get; }
        [DefaultValue(0)]
        int Priority { get; }
    }

Я использовал это, чтобы ответить на вопрос, потому что меня по-прежнему интересует мнение других людей, которые, возможно, уже решили подобную проблему.


person Eggi    schedule 14.05.2012    source источник
comment
Кажется, вам нужен базовый проект, в который вы могли бы внести некоторые изменения в зависимости от каждого клиента. Я правильно понял?   -  person Tulio F.    schedule 22.05.2012
comment
Я хочу иметь (несколько) основной проект, в котором есть (есть) код для каждого клиента, и я также хотел бы иметь специализированные проекты, которые принадлежат только одному клиенту.   -  person Eggi    schedule 22.05.2012


Ответы (1)


О структуре проекта: вы можете создать базовый проект со всеми необходимыми слоями проблем. Модель, бизнес, представления, репозитории и так далее.

Также создайте какой-нибудь базовый поток, например, одно представление со своим контроллером до репозитория. Сохраните его в своей кодовой базе, а затем разветвляйте, когда вам нужно создать новый проект.

Теперь вместо того, чтобы тратить время на настройку, вам просто нужно время, чтобы настроить его в соответствии с требованиями вашего проекта.

О XAML: IMHO, если вы меняете компонент, вы должны быть уверены, что он возвращает тот же тип данных, который ожидает ваш элемент управления. Если вы меняете текстовое поле на флажок, убедитесь, что проверка возвращает строку контроллеру.

person Tulio F.    schedule 22.05.2012
comment
Это решение звучит не очень хорошо для конкретных изменений клиента. Проблема в том, что если у меня есть, скажем, 100 клиентов, и я делаю форк для всех из них, а после этого я нахожу серьезную ошибку в ядре, мне придется применить это исправление ко всем клиентам. - person Eggi; 22.05.2012
comment
Я имел в виду другой контекст. Это не простая проблема, как вы сказали, у клиента могут быть особые требования, которые могут привести к изменениям во всех вышеперечисленных проектах. А это значит, что от кастомизации ничего не спасает. Вы можете попытаться изолировать основные функции, которые могут повторно использоваться всеми пользовательскими экземплярами вашего приложения. - person Tulio F.; 22.05.2012
comment
Поскольку другого ответа не было, я дам тебе награду. - person Eggi; 24.05.2012