WCF可靠性问题

发布于 2024-10-29 02:13:37 字数 2587 浏览 6 评论 0原文

尝试测试我的 wcf 服务的可靠性。我正在从客户端循环内调用 wcf 服务。 WCF REST服务(WebhttpBinding)进行一些数据处理并插入 记录到数据库中。整个操作是在事务内完成的。

我发现,如果我将 InstanceContextMode 设置为 PerCall,则在大约 60 条消息(从循环内部调用服务的 60 倍)中,只有 40 条消息会传递到数据库。没有错误,没有例外。这些消息刚刚被丢弃。

如果我将 InstanceContextMode 设置为 Single,那么我会看到所有消息都到达数据库。 InstanceContextMode.Percall 有损是预期的行为吗?另外,我没有设置并发。任何澄清都会非常有帮助。添加了代码。使用 MySQL 作为数据库...

编辑我的坏处 - 我刚刚注意到我在服务器端遇到异常 - {“尝试获取锁定时发现死锁;尝试重新启动事务”}

这是因为当事务正在进行时,同一记录上调用了另一个事务。如果事务失败一次,可以通过重新启动事务来修复它。

服务

    [WebInvoke(UriTemplate = "employee", Method = "POST")]
    public long AddNewEmployee(EmployeeEntity newEmployee)
    {
        EmployeeRepository eRep = new EmployeeRepository();
        return eRep.AddNewEmployee(newEventEntity);                     
    }

存储库类构造函数初始化对象上下文

    public EmployeeRepository()
    {
        bd = new EmployeeEntity();
    }

代码 - 服务调用

    //bd is the object context 
    //there are two tables 
    internal long AddNewEmployee(EmployeeEntity newEmployee)
    {
        bool tSuccess = false;
        using (TransactionScope transaction = new TransactionScope())
        {
            try
            {
                //get existing employees
                var existingEmployees = from employee
                                        in bd.employees select employee;


                List<employee> returnedEmployees = new List<employee>();                    

                //Do some processing 
                returnedEmployees = DoSomeprocessing(existingEmployees);

                //Insert returned employees as updates
                foreach (employee e in returnedEmployees)
                {
                    bd.employees.AddObject(e);
                }

                bd.SaveChanges();
                returnedEmployees.Clear();

                //add to second table 
                bd.otherdetails.AddObject(newEmployee);
                bd.SaveChanges();


                //Transaction Complete                        
                transaction.Complete();
                tSuccess = true;

            }
            catch (Exception e)
            {
                //return something meaningful 
                return -1;                    
            }
        }

        if (tSuccess)
        {
            //End Transaction
            bd.AcceptAllChanges();
            return 200;
        }            
        else
        {
           return -1;
        }

    }

客户端只是循环调用服务

Trying to test the reliability of my wcf services. I am calling a wcf service within a loop from the client side. The wcf rest service (webhttpbinding) does some data processing and inserts
records into a database. The entire operation is done within a transaction.

I find that out of about 60 messages (60 times the service being called from inside a loop) only 40 are going through to the db if I set my InstanceContextMode to PerCall. There are no errors no exceptions. The messages are just being dropped.

If I set the InstanceContextMode to Single then I see all messages getting to the db.
Is the InstanceContextMode.Percall being lossy the expected behavior? Also, I do not have concurrency set. Any clarifications would be greatly helpful. Added the code. Using MySQL as the db...

EDIT My bad - I just noticed that I get an exception on the server side - {"Deadlock found when trying to get lock; try restarting transaction"}

This is because there is another transaction invoked on the same records while a transaction is under progress. Fixing it by restarting the transaction if it fails once.

The service

    [WebInvoke(UriTemplate = "employee", Method = "POST")]
    public long AddNewEmployee(EmployeeEntity newEmployee)
    {
        EmployeeRepository eRep = new EmployeeRepository();
        return eRep.AddNewEmployee(newEventEntity);                     
    }

The repository class constructor initializes the object context

    public EmployeeRepository()
    {
        bd = new EmployeeEntity();
    }

Code - The service call

    //bd is the object context 
    //there are two tables 
    internal long AddNewEmployee(EmployeeEntity newEmployee)
    {
        bool tSuccess = false;
        using (TransactionScope transaction = new TransactionScope())
        {
            try
            {
                //get existing employees
                var existingEmployees = from employee
                                        in bd.employees select employee;


                List<employee> returnedEmployees = new List<employee>();                    

                //Do some processing 
                returnedEmployees = DoSomeprocessing(existingEmployees);

                //Insert returned employees as updates
                foreach (employee e in returnedEmployees)
                {
                    bd.employees.AddObject(e);
                }

                bd.SaveChanges();
                returnedEmployees.Clear();

                //add to second table 
                bd.otherdetails.AddObject(newEmployee);
                bd.SaveChanges();


                //Transaction Complete                        
                transaction.Complete();
                tSuccess = true;

            }
            catch (Exception e)
            {
                //return something meaningful 
                return -1;                    
            }
        }

        if (tSuccess)
        {
            //End Transaction
            bd.AcceptAllChanges();
            return 200;
        }            
        else
        {
           return -1;
        }

    }

The client side just calls the service in a loop

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一个人的旅程 2024-11-05 02:13:37

我强烈建议为任何 WCF 添加全局异常处理。它帮助我节省了许多时间的调试时间,并且可以捕获任何未处理的异常。它比 ASP.NET 中的 global.ascx 涉及更多一点

步骤 1 - 实现 IErroHander 和 IServiceBehavior

请注意,在 HandleError 中我正在使用 Enterprise Library 来处理异常。您也可以在此处使用您的自定义实现。

 public class ErrorHandler : IErrorHandler, IServiceBehavior
        {        
            public bool HandleError(Exception error)
            {
                // Returning true indicates you performed your behavior.
                return true;
            }


            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {            
                // Log Exception

                ExceptionPolicy.HandleException(error, "ExceptionPolicy");

                // Shield the unknown exception
                FaultException faultException = new FaultException(
                    "Server error encountered. All details have been logged.");
                MessageFault messageFault = faultException.CreateMessageFault();

                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }

            private IErrorHandler errorHandler = null;

            public ErrorHandler()
            {

            }

            public ErrorHandler(IErrorHandler errorHandler)
            {
                this.errorHandler = errorHandler;
            }

            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {

            }
        }

    }

第 2 步 - 创建错误元素

public class ErrorHandlerElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }

        public override Type BehaviorType
        {
            get
            {
                return typeof(ErrorHandler);
            }
        }
    }

第 3 步 - 将元素添加到 web.config

<serviceBehaviors>
        <behavior>                              
          <ErrorHandler />
        </behavior>
      </serviceBehaviors>

I highly suggest adding global exception handling for any WCF. It has helped me save many hours of debugging and will catch any unhandled exceptions. It's a little bit more involved than global.ascx in ASP.NET

Step 1 - Implement IErroHander and IServiceBehavior

Notice inside HandleError I'm using Enterprise Library to handle the exception. You can use your custom implementation here as well.

 public class ErrorHandler : IErrorHandler, IServiceBehavior
        {        
            public bool HandleError(Exception error)
            {
                // Returning true indicates you performed your behavior.
                return true;
            }


            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {            
                // Log Exception

                ExceptionPolicy.HandleException(error, "ExceptionPolicy");

                // Shield the unknown exception
                FaultException faultException = new FaultException(
                    "Server error encountered. All details have been logged.");
                MessageFault messageFault = faultException.CreateMessageFault();

                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }

            private IErrorHandler errorHandler = null;

            public ErrorHandler()
            {

            }

            public ErrorHandler(IErrorHandler errorHandler)
            {
                this.errorHandler = errorHandler;
            }

            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
                foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher cd = cdb as ChannelDispatcher;

                    if (cd != null)
                    {
                        cd.ErrorHandlers.Add(new ErrorHandler());
                    }
                }
            }

            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {

            }
        }

    }

Step 2 - Create Error Element

public class ErrorHandlerElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }

        public override Type BehaviorType
        {
            get
            {
                return typeof(ErrorHandler);
            }
        }
    }

Step 3 - Add Element to web.config

<serviceBehaviors>
        <behavior>                              
          <ErrorHandler />
        </behavior>
      </serviceBehaviors>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文