c# microsoft graph api getAsync() 中的 Windows 服务调用用户进入挂起状态 [英] windows service in c# microsoft graph api getAsync() call for users goes in hung state

查看:31
本文介绍了c# microsoft graph api getAsync() 中的 Windows 服务调用用户进入挂起状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 MS 图形 API 使用线程读取 Windows 服务中的不同邮箱.服务运行了几天,但进入挂起状态.

I am reading different mailboxes in windows service using MS graph api using threads. Service runs well for few days, but after it goes in hung state.

通过观察日志发现卡点是在为users调用GetAsync()方法时,之后它也没有更新日志文件,但服务显示在运行状态.

By observing logs found that stuck point is while calling GetAsync() method for users, after that it is not updating log file also but service is showing in running state.

重启服务后正常运行了几天.

After restarting the service it runs normally for few days.

public static async Task MainAsync()
        {
            Task t1 = ParallelThreadOne.MainAsync();
            Task t2 = ParallelThreadSecond.MainAsync();
            Task t3 = ParallelThreadThird.MainAsync();            
            
            await Task.WhenAll(t1, t2, t3);

        }

 public static async Task MainAsync()
        {

            try
            {                
                EmailMaster objEmailMaster = new EmailMaster();

                List<MailBoxConfiguration> lstMailBoxConfiguration = objEmailMaster.GetMailBoxInformation(1,logger);
                if (lstMailBoxConfiguration != null)
                {
                    if (lstMailBoxConfiguration.Count != 0)
                    {                        
                        GraphServiceClient client = GetAuthenticatedClient();
                       
                        if (client != null)
                        {
                            for (int j = 0; j < lstMailBoxConfiguration.Count; j++)
                            {                                
                                var users = await graphClient
                                .Users
                                .Request()
                                .Filter("startswith(Mail,'" + lstMailBoxConfiguration[j].EmailId + "')")
                                .GetAsync();                               
                                
                                if (users.Count > 0)
                                {                                   
                                    var msgs = await graphClient
                                           .Users[users[0].Id]
                                           .MailFolders["Inbox"].Messages
                                           .Request().Top(500)
                                           .GetAsync();
                                     
                                        if (msgs.Count > 0)
                                        {
                                            foreach (var item in msgs)
                                            {                                                
                                                //business logic goes here                                                
                                            }
                                        }
                                        else
                                        {
                                            logger.Info("msg.Count is zero");
                                        }
                                }
                                else
                                {
                                    logger.Info("users.Count is zero");
                                }
                            }
                        }
                        else
                        {
                            logger.Info("client is null");
                        }
                    }
                    else
                    {
                        logger.Info("lstMailBoxConfiguration.Count is zero from the database");
                    }
                }
                else
                {
                    logger.Info("lstMailBoxConfiguration is null from the database");
                }
                logger.Info("MainAsync(1) : End of MainAsync(1)");
            }
            catch (Exception ex)
            {
                logger.Error("MainAsync(1) : Exception : " + ex.Message);
            }

        }
        public static GraphServiceClient GetAuthenticatedClient()
        {
            
            string clientId = ConfigurationManager.AppSettings["AzureClientId"];
            string password = ConfigurationManager.AppSettings["password"];           
            string tenantId = ConfigurationManager.AppSettings["tenantId"];
            string getTokenUrl = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";           
            const string grantType = "client_credentials";
            const string myScopes = "https://graph.microsoft.com/.default"; 
            string postBody = $"client_id={clientId}&scope={myScopes}&client_secret={password}&grant_type={grantType}";
            try
            {                             
                if (graphClient == null)
                {
                    graphClient = new GraphServiceClient(

                      "https://graph.microsoft.com/v1.0",
                        new DelegateAuthenticationProvider(
                            async (requestMessage) =>
                            {                         
                            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, getTokenUrl);
                                httpRequestMessage.Content = new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded");                         
                                HttpResponseMessage httpResponseMessage = await client.SendAsync(httpRequestMessage);
                            string responseBody = await httpResponseMessage.Content.ReadAsStringAsync();
                                userToken = JObject.Parse(responseBody).GetValue("access_token").ToString();
                                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", userToken);
                            }));
                }
                return graphClient;
            }
            catch (Exception ex)
            {
                logger.Error("Could not create a graph client: " + ex.Message);
            }
            finally
            {
                logger.Info("GetAuthenticatedClient() :inside finally!");   
            }

            return graphClient;
        }

推荐答案

通过查看 GraphServiceClient 的源代码,它使用 HTTPClient 作为其底层通信提供程序.HTTPClient 有一个问题,因为在处理 HTTPClient 后,Windows 会在一定时间内保持 TCP/IP 连接打开.如果你在 HTTPClient 类上调用 new 然后 dispose 足够快,它会导致套接字饥饿.(注意,当实例超出范围时,using(var client = new HTTPClient()) 会在幕后调用 dispose)

From looking through the source code of the GraphServiceClient, it is using HTTPClient as its underlying communication provider. The HTTPClient has an issue because windows keeps TCP/IP connections open for a certain amount of time after the HTTPClient is disposed. If you call new and then dispose on the HTTPClient class fast enough for long enough it can lead to socket starvation. (note, using(var client = new HTTPClient()) calls dispose under the covers when the instance goes out of scope)

查看有关此问题的这篇博文.https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

Take a look at this blog post on the issue. https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

您应该能够使用 GraphServiceClient 的单个实例,只要您与同一个 GraphQL 端点通信并解决服务挂起的问题.如果您添加日志记录,您可能会注意到服务在一系列活动后挂起,导致 GraphServiceClient 的大量新实例被创建,然后在短时间内处理,并且您在服务器上打开网络连接爆炸导致错误,使您的一个线程崩溃.

You should be able to use a single instance of the GraphServiceClient as long as you are talking to the same GraphQL endpoint and fix your issues with the service hanging. If you add logging you will probably notice that the service hangs after a flurry of activity causing lots of new instances of the GraphServiceClient to be created then disposed in a short time frame and your open network connections on the server exploding causing an error that crashes one of your threads.

这篇关于c# microsoft graph api getAsync() 中的 Windows 服务调用用户进入挂起状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆