我有以下精简的 DTO:

[DataContract]
public class ChartDefinitionBase
{
    [DataMember]
    public string Id { get; private set; }
}

...以及以下精简的 Mongo 服务定义:
public class MongoChartService : IChartService
{
    private readonly IMongoCollection<ChartDefinitionBase> _collection;
    private const string _connectionStringKey = "MongoChartRepository";

    internal MongoChartService()
    {
        // Exception occurs here.
        BsonClassMap.RegisterClassMap<ChartDefinitionBase>(cm =>
        {
                cm.AutoMap();
                cm.MapIdMember(c => c.Id).SetIdGenerator(StringObjectIdGenerator.Instance);
        });
        var connectionString = ConfigurationManager.ConnectionStrings[_connectionStringKey].ConnectionString;
        var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
        var client = new MongoClient(settings);
        var database = client.GetDatabase(ConfigurationManager.ConnectionStrings[_connectionStringKey].ProviderName);
        _collection = database.GetCollection<ChartDefinitionBase>("Charts");
    }

    public void Create(ChartDefinitionBase instance)
    {
        _collection.InsertOne(instance);
    }

    public IEnumerable<ChartDefinitionBase> GetAllCharts()
    {
        var charts = _collection.Find(_ => true).ToList();
        return charts;
    }
}

然后我有一个客户端库,它有一个名为 MongoChartServiceChartServiceClient 的 WCF 服务引用。

当我直接创建一个MongoChartService的实例并注入(inject)一个ChartDefinitionBase的实例(完全实现并且没有子类)时,我就可以完成一次到数据库的往返(创建、读取、删除)。如果我创建 ChartServiceClient 的一个实例并尝试使用精简的 DTO 重复相同的步骤,则在调用 ServiceModel.FaultException 时会得到一个 GetAllCharts,其中 ExceptionDetail “已添加具有相同键的项目。”这是带有注释的示例单元测试。
    [TestMethod, TestCategory("MongoService")]
    public void ChartServiceClient_CRD_ExecutesSuccessfully()
    {
        SetupHost();
        using (var client = new ChartServiceClient())
        {
            client.Create(_dto); // Create method succeeds.  Single entry in dB with Mongo-generated ID.
            ChartDefinitionBase dto = null;
            while (dto == null)
            {
                var dtos = client.GetAllCharts(); // Exception occurs here.
                dto = dtos.SingleOrDefault(d => d.Id == _dto.Id);
            }
            client.Delete(_dto);
            while (dto != null)
            {
                var dtos = client.GetAllCharts();
                dto = dtos.SingleOrDefault(d => d.Id == _dto.Id);
            }
        }
    }

堆栈跟踪如下:
Server stack trace:
   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at QRPad.Spc.DataLayer.Charts.Service.Client.ServiceReference.IChartService.GetAllCharts()
   at QRPad.Spc.DataLayer.Charts.Service.Client.ServiceReference.ChartServiceClient.GetAllCharts()

编辑: 请注意,异常似乎发生在调用 BsonClassMap.RegisterClassMap 时。这个方法似乎同时被 CreateGetAllCharts() 调用。

任何人都知道发生了什么以及如何解决这个问题?

最佳答案

问题似乎是由于在 BsonClassMap.RegisterClassMap 的构造函数中放置了对 MongoChartService 的调用。直接使用 MongoChartService 时,构造函数只调用一次。使用 ChartServiceClient 时,MongoChartService 构造函数在 Create 上调用一次,在 GetAllCharts 上调用一次;然而,由于 ChartDefinitionBase 是第一次注册的,第二次尝试注册它会产生异常。

当我在 BsonIdAttribute 上使用 Id 或将调用移动到其他地方的 BsonClassMap.RegisterClassMap 时,问题就解决了,例如在对客户端的调用之上:

[TestMethod, TestCategory("MongoService")]
public void ChartServiceClient_CRD_ExecutesSuccessfully()
{
    SetupHost();
    BsonClassMap.RegisterClassMap<ChartDefinitionBase>(cm =>
    {
        cm.AutoMap();
        cm.MapIdMember(c => c.Id).SetIdGenerator(StringObjectIdGenerator.Instance);
    });
    using (var client = new ChartServiceClient())
    {
        client.Create(_dto);
        ChartDefinitionBase dto = null;
        while (dto == null)
        {
            var dtos = client.GetAllCharts();
            dto = dtos.SingleOrDefault(d => d.Id == _dto.Id);
        }
        client.Delete(_dto);
        while (dto != null)
        {
            var dtos = client.GetAllCharts();
            dto = dtos.SingleOrDefault(d => d.Id == _dto.Id);
        }
    }
}

MongoDb documentation 对此进行了说明,尽管我没有意识到服务构造函数会被多次调用:

关于c# - 为什么 WCF/Mongo 会抛出异常 : An item with the same key has already been added,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37078116/

10-15 21:57