小编Rep*_*Man的帖子

如何在严格分层的架构中拆分层并促进模块化而不会造成不必要的冗余?

我已经收到了开始为我公司的代码库建立新架构的基础.这一举措的推动力是:

  • 我们的代码库已有十多年的历史,并且在我们尝试扩展时最终打破了接缝.
  • 如果你想称它们为顶层的"层",那就是传统的ASP和.NET.
  • 我们的数据库充满了一堆不圣洁的存储过程,其中包含数千行业务逻辑和验证.
  • 以前的开发人员创建了"聪明"的解决方案,这些解决方案是不可扩展的,不可重用的,并且表现出非常明显的反模式; 这些需要在短期内弃用.

我一直在引用MS模式与实践架构指南相当严重,我向初始设计工作,但我仍然有一些挥之不去的问题之前,我承诺什么.在我进入问题之前,这是我迄今为止的架构:

(高水平)

高水平

(业务和数据层深入)

业务和数据层深入

这些图基本上显示了我打算如何将每个层分成多个组件.所以在这个候选架构中,我们有11个组件,不包括最顶层.

这是故障,每个组件的描述:

  • Company.Project.Common.OperationalManagement :包含实现异常处理策略,日志记录,性能计数器,配置和跟踪的组件.
  • Company.Project.Common.Security :包含执行身份验证,授权和验证的组件.
  • Company.Project.Common.Communication :包含可用于与其他服务和应用程序(基本上是一堆可重用的WCF客户端)通信的组件.
  • Company.Project.Business.Interfaces :包含用于从高级层与业务层交互的接口和抽象类.
  • Company.Project.Business.Workflows :包含与业务工作流的创建和维护相关的组件和逻辑.
  • Company.Project.Business.Components :包含封装业务规则和验证的组件.
  • Company.Project.Business.Entities:包含代表高级业务实体的数据对象.其中一些可能是唯一的,一些可能是由来自数据层的更精细数据实体形成的复合材料.
  • Company.Project.Data.Interfaces :包含用于与存储库样式中的数据访问层交互的接口和抽象类.
  • Company.Project.Data.ServiceGateways :包含用于从外部系统调用和获取数据的服务客户端和组件.
  • Company.Project.Data.Components :包含用于与数据库通信的组件.
  • Company.Project.Data.Entities :包含更多粒度实体,这些实体表示低级别的业务数据,适合以事务方式持久保存到数据库或其他数据源.

我的意图是这应该是一个严格的分层设计(一个层可能只与它下面的层通信),层的模块化破坏应该促进高内聚和松散耦合.但我仍有一些担忧.以下是我的问题,我认为这些问题足够客观,以至于它们适用于此...

  1. 我的每个模块及其各自的程序集的命名约定是否遵循标准约定,或者我应该采用不同的方式进行此操作?
  2. 将业务和数据层分成多个程序集是否有益?
  3. 在自己的程序集中为每个层设置接口和抽象类是否有益?
  4. 最重要的是 - 为业务层和数据层提供"实体"程序集是否有益?我关注的是,如果在数据访问组件中包含将由LINQ to SQL生成的类,则给定实体将在代码库中的三个不同位置表示.显然,像AutoMapper这样的工具可能会有所帮助,但我仍然不是100%.我有他们碎裂开这样的原因是为了A -执行严格的分层体系结构和B -促进层之间的松耦合,并且当改变到各实体背后的业务域发生最小化破损.但是,我想从那些比我更有经验的建筑师那里获得一些指导.

如果你能回答我的问题或指出我正确的方向,我将非常感激.谢谢.


编辑:想要在阅读狒狒的答案之后加入一些似乎更相关的其他细节.数据库表也是一个不圣洁的混乱,充其量只是准关系.不过,我不能完全重新构建数据库,并做了数据清理:最远到核心我可以去是创建新的存储的特效,并开始弃用旧的.这就是为什么我倾向于在所述数据层明确定义的实体 - 尝试使用的数据实体的LINQ产生的SQL(或任何其他的ORM)的类只是似乎并不可行.

.net c# architecture

23
推荐指数
2
解决办法
5342
查看次数

使用LINQ ExpressionVisitor将基本参数替换为lambda表达式中的属性引用

我正在为我们系统的一部分编写数据层,该数据层记录有关每天运行的自动作业的信息 - 作业名称,运行时间,结果,等等.

我正在使用Entity Framework与数据库交谈,但我试图将这些细节隐藏在更高级别的模块之外,我不希望实体对象本身被暴露.

但是,我想使我的界面在用于查找作业信息的标准中非常灵活.例如,用户界面应允许用户执行复杂的查询,例如"给我所有名为'hello'的作业,该作业在上午10:00到11:00之间运行失败." 显然,这看起来像是动态构建Expression树的工作.

所以我希望我的数据层(存储库)能够接受类型Expression<Func<string, DateTime, ResultCode, long, bool>>(lambda表达式)的LINQ表达式,然后在后台将该lambda转换为我的实体框架ObjectContext可以用作Where()子句中的过滤器的表达式.

简而言之,我正在尝试将类型的lambda表达式转换Expression<Func<string, DateTime, ResultCode, long, bool>>Expression<Func<svc_JobAudit, bool>>,其中svc_JobAuditEntity Framework数据对象对应于存储作业信息的表.(第一个委托中的四个参数分别对应于作业名称,运行时间,结果以及分别在MS中花费的时间)

我在使用该ExpressionVisitor课程时取得了很好的进展,直到我碰到了一堵砖墙并收到了一条InvalidOperationException错误消息:

从"VisitLambda"调用时,重写"System.Linq.Expressions.ParameterExpression"类型的节点必须返回相同类型的非null值.或者,覆盖"VisitLambda"并将其更改为不访问此类型的子项.

我完全不知所措.为什么它不允许我将引用参数的表达式节点转换为引用属性的节点?还有另一种方法可以解决这个问题吗?

以下是一些示例代码:

namespace ExpressionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<string, DateTime, ResultCode, long, bool>> expression = (myString, myDateTime, myResultCode, myTimeSpan) => myResultCode == ResultCode.Failed && myString == "hello";
            var result = ConvertExpression(expression);
        }

        private static Expression<Func<svc_JobAudit, bool>> …
Run Code Online (Sandbox Code Playgroud)

c# linq lambda expression visitor

13
推荐指数
2
解决办法
1万
查看次数

创建单个ChannelFactory <T>并重用客户端连接

在我们的SharePoint/ASP.NET环境中,我们有一系列数据检索器类,这些类都来自通用接口.我被分配了创建数据检索器的任务,该数据检索器可以使用WCF与其他SharePoint场远程通信.我现在实现它的方式ChannelFactory<T>是在静态构造函数中创建单例,然后由远程数据检索器的每个实例重用,以创建单独的代理实例.我认为这样可以很好地工作,因为那时ChannelFactory只在app域中实例化一次并且它的创建保证是线程安全的.我的代码看起来像这样:

public class RemoteDataRetriever : IDataRetriever
{
    protected static readonly ChannelFactory<IRemoteDataProvider>
        RequestChannelFactory;

    protected IRemoteDataProvider _channel;

    static RemoteDataRetriever()
    {
        WSHttpBinding binding = new WSHttpBinding(
            SecurityMode.TransportWithMessageCredential, true);

        binding.Security.Transport.ClientCredentialType =
            HttpClientCredentialType.None;

        binding.Security.Message.ClientCredentialType =
            MessageCredentialType.Windows;

        RequestChannelFactory = 
            new ChannelFactory<IRemoteDataProvider>(binding);
    }

    public RemoteDataRetriever(string endpointAddress)
    {
        _channel = RemoteDataRetriever.RequestChannelFactory.
            CreateChannel(new EndpointAddress(endpointAddress));
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这是一个很好的设计吗?我想,一旦ChannelFactory创建,我不需要担心线程安全,因为我只是用它来打电话,CreateChannel()但我错了吗?它是在改变状态还是在幕后做一些可能导致线程问题的时髦的东西?另外,我是否需要在某个地方放置一些代码(静态终结器?)来手动处理ChannelFactory或者我可以假设每当IIS重新启动它时,它会为我做所有的清理工作吗?

相关:ChannelFactory重用策略

wcf singleton static-constructor thread-safety channelfactory

10
推荐指数
1
解决办法
1万
查看次数

在winforms应用程序中缓存GDI +对象:是否值得,如何正确执行?

对于我的一些winforms应用程序,我需要创建一大堆GDI +对象(画笔,笔,字体等)并一遍又一遍地使用它们.我创建了一个贫民窟缓存单身人士来完成我需要的东西,但代码味道压倒性......

public sealed class GraphicsPalette
{
    public static readonly GraphicsPalette Instance = new GraphicsPalette();

    static GraphicsPalette()
    {
    }

    private Dictionary<Color, Brush> solidBrushes;

    //multithreading
    private object brushLock;

    private GraphicsPalette()
    {
        solidBrushes = new Dictionary<Color, Brush>();

        brushLock = new object();
    }

    public Brush GetSolidBrush(Color color, int alpha)
    {
        return GetSolidBrush(Color.FromArgb(alpha, color));
    }

    public Brush GetSolidBrush(Color color)
    {
        if (!solidBrushes.ContainsKey(color))
        {
            lock (brushLock)
            {
                if (!solidBrushes.ContainsKey(color))
                {
                    Brush brush = new SolidBrush(color);
                    solidBrushes.Add(color, brush);
                    return brush;
                }
            }
        }
        return solidBrushes[color];
    } …
Run Code Online (Sandbox Code Playgroud)

.net c# system.drawing gdi+ winforms

10
推荐指数
1
解决办法
1963
查看次数

WCF REST服务 - 401未经授权

我们正在开发一个WCF REST Web服务,它只接收来自任何匿名用户的大量任意文本,然后在后端执行一些处理.

例如,这是我们的Web服务中的一种方法:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MyRESTService : IMyRESTService
{
    [WebInvoke(Method = "PUT", UriTemplate = "/MyRESTMethod?paramA={paramA}&paramB={paramB}")]
    public Stream MyRESTMethod(string paramA, string paramB, Stream rawData)
    {
        //do some stuff...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们只使用默认的IIS设置,我们得到一个(401) Unauthorized.然而,在经过多次反复试验后,我们发现我们可以通过在实际.svc文件上为我们的服务提供WRITE访问权限来使其工作.

我的问题是:为什么IIS需要对.svc文件进行WRITE访问以使其工作?有没有更好的方法,还是我坚持这种hackish(可能不安全)的解决方法?

WTF微软?

可能相关:

iis rest wcf iis-7 http-status-code-401

8
推荐指数
2
解决办法
1万
查看次数

将多个参数传递给Threading.Timer回调方法的最佳方法是什么?

在我过去的几个项目中,我遇到了需要将多个参数传递给Threading.Timer回调方法的情况.不幸的是,构造函数只接受一个object参数.不想使用全局变量,我开始用来克服这个问题的模式是在创建计时器时传入一个匿名方法,并使用编译器捕获变量的能力,如下所示:

public void SendEmailsRepeatedly(IEnumerable<SimpleEmail> emails, int sendRepeatedlyDelayMS)
{
    Tokenizer tokenizer = new StandardTokenizer();

    sendRepeatedlyTimer = new Timer(
        SendRepeatedlyCallback,
        (Action)delegate()
        {
            TokenizeAndSendEmails(emails, tokenizer);
        },
        0,
        sendRepeatedlyDelayMS);
}

private void SendRepeatedlyCallback(object state)
{
    if (!abort)
    {
        Action sendEmails = (Action)state;
        sendEmails();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,这是一个公然的黑客攻击吗?是否有更好或推荐的方法来做到这一点?

.net c# timer callback

7
推荐指数
2
解决办法
6527
查看次数

什么是System.ServiceModel.Diagnostics.CallbackException以及为什么我无法处理它?

在我的WCF客户端类中,我正在处理Faulted()事件,以便如果远程服务抛出异常并使通道出错,我仍然可以至少正常地关闭它.这是我的代码:

protected void RemoteDataRetriever_Faulted(object sender, EventArgs e)
{
    (sender as ICommunicationObject).Abort();
    this.Dispose();
    throw new ChannelTerminatedException("The remote service threw an unhandled exception and as a result the channel has been closed.");
}
Run Code Online (Sandbox Code Playgroud)

所以我期望的是客户端可以处理ChannelTerminatedException我手动抛出的并向用户发送消息等等.相反,我的例外是包装在一个System.ServiceModel.Diagnostics.CallbackException.好的.除了这里是catch:ServiceModel库中不存在这个CallbackException,除了作为泛型之外,我似乎无法处理它Exception,这对我的单元测试没有好处.到底发生了什么事?我可以以某种方式禁用它并抛出我最初想要的异常吗?

.net wcf exception-handling exception faulted

6
推荐指数
1
解决办法
6788
查看次数

企业库日志记录:自定义跟踪侦听器,它将消息发送到任意WCF端点

我正在尝试为Enterprise Library Logging编写一个自定义跟踪侦听器,它将所有日志消息发送到任意WCF端点.这背后的想法是我可以在另一端设置一个简单的控制台应用程序,它可以实时打印出所有日志消息.

我的问题分为两部分:

  1. 有没有一种机制可以做到这一点?我已经查看了MSMQ监听器,我对使用它并不感兴趣,因为我可能需要在某些时候使用不同的协议/绑定.
  2. 我在下面实现它的方式 - 它是否足够有效还是有更好的方法?我担心的是每次来自Logger的消息(可能经常发生)我都会打开一个新频道,然后关闭它.这会导致性能问题吗?

在我的样本中RemoteClient派生自ClientBase<T>.

[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class RemoteTraceListener : CustomTraceListener
{
    public override void Write(string message)
    {
        RemoteClient client = new RemoteClient();
        client.Open();
        client.Write(message);
        client.Close();
    }

    public override void WriteLine(string message)
    {
        RemoteClient client = new RemoteClient();
        client.Open();
        client.WriteLine(message);
        client.Close();
    }

    public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
    {
        if (data is LogEntry && this.Formatter != null)
        {
            WriteLine(this.Formatter.Format(data as LogEntry));
        }
        else
        {
            WriteLine(data.ToString()); …
Run Code Online (Sandbox Code Playgroud)

c# wcf logging enterprise-library trace-listener

5
推荐指数
1
解决办法
3244
查看次数

F#报价对任何事情都有用吗?

我认为我可以使用引号来完成我想做的事情(创建一个表达式树,我可以将其存储在数据库中并在以后执行)。但是,令我非常沮丧的是,我了解到报价不可序列化且无法编译(我想避免使用F#PowerPack,因为性能很差)。

因此,我很想知道,F#报价对所有内容都有用吗?如果无法将其编译回代码,那么表示代码的数据结构有什么用?我在这里想念什么?

相关: F#报价的另一个限制? 什么是F#报价?

f# functional-programming metaprogramming

4
推荐指数
1
解决办法
540
查看次数

TypeMock 中的 [TestMethod] 属性在哪里?

好吧,愚蠢的问题。我正在尝试在 VS2005 中设置我的第一个 TypeMock 演示项目,但它无法识别 [TestMethod] 属性。我已包含 TypeMock 和 TypeMock.ArrangeActAssert 程序集,并使用“using”语句引用它们。即使智能感知也找不到该属性。我在这里做错了什么?

.net c# testing typemock

3
推荐指数
1
解决办法
3844
查看次数