none
Проблема с потоками в Web-Service RRS feed

  • Вопрос

  • Есть веб-сервис и в нем веб-метод, который создает второстепенный поток. В качестве аргумента в поток передаю экземпляр класса, далее неоходимо работать со свойствами этого класса. Но вот ту начинает проблема, при любом обращении к этим свойствам, поток подвисает. Долго копался, пробовал всевозможные способы создания отдельного потока. В итоге в метод засунул след код:

    try
    {
        using (StreamWriter sw = new StreamWriter(@"C:\Temp\test.txt"))
        {
            for (int i = 0; i < 1000000; i++)
                sw.WriteLine(i);
        }
    }
    catch(Exception ex)
    {
        Logger.Write(string.Format("{1}{0}{1}{2}",
               ex.Message, Environment.NewLine, ex.StackTrace));
    }

    последнее значение в файле 936518, при этом в лог падает ошибка

    [16.08.2012 10:57:48]
    Поток находился в процессе прерывания.
    в System.Number.FormatInt32(Int32 value, String format, NumberFormatInfo info)
    в System.IO.TextWriter.Write(Int32 value)
    в System.IO.TextWriter.WriteLine(Int32 value)
    в ConnectionPoint.PackageManager.CreatePackages(Object obj) в C:\Projects\ConnectionPoint\ConnectionPoint\PackageManager.cs:строка 112

    Получается, что поток обрывается, как только заканчивает свою работу метод, его породивший. Но это еще не все. Если Виртуальный каталог в диспетчере служб ИИС направить на папку с проектом(сервисом), созданную студией, то все работает, если же на папку, в которой лежит копия проект и создана она ручками, то не работает. Полез в свойства папок, нашел одно различие в разделе Безопасность - в созданной студией папке есть NETWORK SERVICE. Добавил, накидал прав, папки по свойствам уровнял. Не работает. В чем причина, у кого какие мысли есть?



    16 августа 2012 г. 8:22

Ответы

Все ответы

  • Добрый день.

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

    Если из дочернего потока вам не надо возвращать данные в метод, то создавайте не поток, а процесс (надо убедиться, что процессы у вас всегда будут заканчиваться, но и в этом случае, при большом количестве запросов сервер будет тормозить). Если вам надо дожидаться ответа от дочернего потока, то используйте объекты синхронизации. Например: AutoResetEvent.

    16 августа 2012 г. 9:47
    Отвечающий
  • Алексей, процессы нельзя, запросов может быть много, боюсь загружу систему сильно. Потоки как мне кажется самое оптимальное. Но почему, если сервис имеет в качестве физического пути папку созданную студией, всё работает, если же паку созданную пользователем, не работает. Разрешения и права я сравнивал, всё одинаково.
    16 августа 2012 г. 10:10
  • "В качестве аргумента в поток передаю экземпляр класса" - что за экземпляр? Вы случайно не делите одни и те же ресурсы между потоками?

    "Если Виртуальный каталог в диспетчере служб ИИС направить на папку с проектом(сервисом), созданную студией, то все работает, если же на папку, в которой лежит копия проект и создана она ручками, то не работает. Полез в свойства папок, нашел одно различие в разделе Безопасность - в созданной студией папке есть NETWORK SERVICE. Добавил, накидал прав, папки по свойствам уровнял. Не работает. В чем причина, у кого какие мысли есть?" - права тут не причём. Виртуальный каталог создаёт сама студия она же и конфигурирует его. А чтобы создать новый, создайте виртуальный каталог и сконфигурируйте его из консоли IIS, а в качестве физического пути укажите его (созданную пользователем).

    16 августа 2012 г. 10:20
    Модератор
  • У меня есть ощущение, что вы пытаетесь получить доступ к папке не входящий в папку веб-приложения. Может IIS режет...

    16 августа 2012 г. 10:20
    Отвечающий
  • Ниже кусок кода, метод веб-сервиса, класс который порождает вторичный поток:

    [WebMethod(Description = "Генерация пакета сведений")]
    public string CreatePackage(string sessionId, string objectCode,
        bool historyCreate, bool documentInclude, string filter)
    {
        try
        {
            SessionDAO sDAO = DataLoader<SessionDAO>.Load(Entities.Session.DBPath);
            if (!sDAO.CheckSession(sessionId))
                return ErrorEnumeration.WrongSessionID;
    
            if (ConfigManager.Objects.Count(o => o.Code == objectCode) == 0)
                return ErrorEnumeration.NullObject;
    
            PackageDAO pDAO = DataLoader<PackageDAO>.Load(Entities.Package.DBPath);
            string id = pDAO.CreatePackage(objectCode);
            if (!string.IsNullOrEmpty(id))
            {
                new PackageManager(id, objectCode, filter).Create();
                return string.Format("<package id='{0}'/>", id);
            }
            else
                return ErrorEnumeration.NullPackage;
        }
        catch(Exception ex)
        {
            Logger.Write(string.Format("Ошибка создания пакета: {1}{0}{1}{2}",
                ex.Message, Environment.NewLine, ex.StackTrace));
            return ErrorEnumeration.SystemError;
        }
    }
        public class PackageManager
        {        
            /// <summary>
            /// ИД пакета
            /// </summary>
            public string PackageId { get; set; }
    
            /// <summary>
            /// Код объекта
            /// </summary>
            public string ObjectCode { get; set; }      
    
            /// <summary>
            /// Фильтр
            /// </summary>
            public string Filter { get; set; }       
    
            /// <summary>
            /// Конструктор класса
            /// </summary>
            /// <param name="packageId">ИД пакета</param>
            /// <param name="objectCode">Код объекта</param>
            /// <param name="filter">Фильтр</param>
            public PackageManager(string packageId, string objectCode, string filter)
            {
                this.PackageId = packageId;
                this.ObjectCode = objectCode;
                this.Filter = filter;            
            }
    
            /// <summary>
            /// Создание файла
            /// </summary>
            public void Create()
            { 
                System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(Run), this);         
            }
        }

    Это все, в методе Run аргумент входящий преобразуется к классу PackageManager и далее использую 3 сво-ва из этого класса.

    Наверное, Вы не поняли, нет конфликта. Есть папка, например, C:\TestService и есть папка C:\Projects\ConnectionPoint. Первую я сам создаю, вторую студия, когда проект создавал. Содержимое первой - это копия проекта из второй. Далее создаю в Диспетчере служб ИИС виртуальный каталог и указываю физический путь вторую папку. В тестовом приложении добавляю веб ссылку, она имеет URL вида http:\\SomeIP\ConnectionPoint\Class.asmx, создаю экземпляр веб-класса, дергаю метод, порождающий потоки, всё ок, нужная информация генерируется, тестовое приложение не ожидает завершения метода, ибо он отрабатывает быстро. Далее у вирутального каталога меняю визический путь на первую папку, и запускаею тестовое приложение. Происходит ошибка, которую описал выше.




    16 августа 2012 г. 10:50
  • тема актуальна
    20 августа 2012 г. 6:59
  • У вас в первом сообщении есть вот такой путь: C:\Temp\test.txt. Меняя путь к веб сервису, вы меняете и его?

    20 августа 2012 г. 7:05
    Отвечающий
  • У вас в первом сообщении есть вот такой путь: C:\Temp\test.txt. Меняя путь к веб сервису, вы меняете и его?


    Зачем?) Это просто как бы заглушка, проверяю прерывается ли поток или отрабатывает
    20 августа 2012 г. 10:20
  • Привет.

    А что вы делаете с файлом, только читате или еще изменяете его?

    Посмотрите System.Threading.ThreadAbortException when executing remote web service может быть эта тема поможет вам с выяснением причин такого поведения.


    Для связи [mail]

    • Помечено в качестве ответа Abolmasov Dmitry 3 сентября 2012 г. 11:11
    23 августа 2012 г. 8:50