Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> WebMethod vs Returned Object 
:(
    Опции темы
neutrino
Дата 2.3.2007, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Приветствую!

У меня наверняка ламерский вопрос. Если webMethod возвращает объект и мне нужно вызвать метод этого объекта, то он тоже должен быть WebMethod? Можно пример пожалуйста.

Спасибо.

С уважением, нейтрино.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neutrino
Дата 3.3.2007, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Детализирую ситуацию.

Есть класс А, который возвращается после выполнения
Код

[WebMethod] public A getA()
{
return this.a;
}


Класс А определен:
Код

[Serializable]
public class A
{
     private int value;

public int getValue()
{
return value;
}
}


После того, как я генерирую прокси (с помощью wsdl), клиент не знает какие поля и методы есть у класса А (впрочем и в Web Reference тоже нет).  Как можно вызвать А.getValue() ???


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
mr.DUDA
Дата 3.3.2007, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 2
Всего: 232



ИМХО, передавать A на клиент полностью, со всеми свойствами. Или же объявить А веб-сервисом, сгенерировать для него прокси и гонять этот прокси между клиентом и сервером -- что есть криво и к тому же придётся перед вызовом getValue устанавливать а.Url


--------------------
user posted image
PM MAIL WWW   Вверх
neutrino
Дата 3.3.2007, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Цитата(mr.DUDA @  3.3.2007,  12:14 Найти цитируемый пост)
ИМХО, передавать A на клиент полностью, со всеми свойствами.

Как именно?

Добавлено @ 19:03 
Цитата(neutrino @  3.3.2007,  17:56 Найти цитируемый пост)
Как именно? 

Вернее интересует именно код. Все, что я пытался сделать не работало.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
mr.DUDA
Дата 3.3.2007, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 2
Всего: 232



neutrino, всё что нужно - добавить в класс конструктор без параметров (для десериализации), и у всех свойств кроме get завести ещё set (для сериализации в XML). Проверил на простом примере у себя:

MyService.cs
Код
using System;
using System.Web.Services;

[WebService]
public class MyService
{
    public MyService ()
    {
    }

    [WebMethod]
    public Class1 HelloWorld(int x, int y)
    {
        return new Class1(x, y);
    }    
}


Class1.cs (его передаём на клиент)
Код
using System;

public class Class1
{
    // конструктор без параметров для десериализации
    protected Class1()
    {
    }

    public Class1(int x, int y)
    {
        _z = x + y;
    }

    int _z;
    public int Z
    {
        get
        {
            return _z;
        }
        set
        {
            _z = value;
        }
    }
}


Код клиента (веб-референс добавил под именем MyServiceProxy):
Код
using System;

using ConsoleApplication2.MyServiceProxy;

class Program
{
    static void Main()
    {
        MyService service = new MyService();
        Class1 result = service.HelloWorld(1, 2);

        Console.WriteLine(result.Z);
    }
}



--------------------
user posted image
PM MAIL WWW   Вверх
neutrino
Дата 5.3.2007, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



mr.DUDA, премного благодарен за помощь, но... Можно я тебя еще подостаю?

Цитата(mr.DUDA @  3.3.2007,  18:30 Найти цитируемый пост)
всё что нужно - добавить в класс конструктор без параметров (для десериализации)

done.

Цитата(mr.DUDA @  3.3.2007,  18:30 Найти цитируемый пост)
и у всех свойств кроме get завести ещё set (для сериализации в XML)

У меня нет свойств.

Цитата(mr.DUDA @  3.3.2007,  18:30 Найти цитируемый пост)
Проверил на простом примере у себя:

Вот класс, который необходимо вернуть:

Код

namespace core.commands
{
    /// <summary>
    /// Class represents response of command.
    /// </summary>
    [Serializable]
    public class CommandResponse
    {
        private object data;
        private bool succeed;

        public CommandResponse()
        {
        }

        public CommandResponse(bool succeed, object data)
        {
            this.data = data;
            this.succeed = succeed;
        }

        public object getData()
        {
            return data;
        }

        public bool commandSucceed()
        {
            return succeed;
        }
    }
}


Сервис:
Код

using System.Web.Services;
using System.Web.Services.Protocols;
using core.facade;
using core.commands;

namespace core.engine
{
    [WebService(Namespace = "http://localhost:1034/WebSite1")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class WebMonitoringService : System.Web.Services.WebService
    {
        private MonitoringEngine monitoringEngine;
        private ServiceFacade serviceFacade;

        public WebMonitoringService()
        {
            this.monitoringEngine = new MonitoringEngine(5, 2000);
            this.serviceFacade = new ServiceFacade(this.monitoringEngine);
        }

        [WebMethod]
        public CommandBase createCommand(string commandLine)
        {
            int firstSpaceCharPosition = commandLine.IndexOf(' ');
            string command;
            string parameters;

            if (firstSpaceCharPosition == -1)
            {
                command = commandLine;
                parameters = "";
            }
            else
            {
                command = commandLine.Substring(0, firstSpaceCharPosition);
                parameters = commandLine.Substring(firstSpaceCharPosition + 1);
            }
            return (CommandBase)this.serviceFacade.createCommand(command, parameters);
        }

        [WebMethod]
        public CommandResponse performCommand(CommandBase command)
        {
            try
            {
                return this.serviceFacade.performCommand(command);
            }
            catch (core.exceptions.MonitoringEngineException ex)
            {
                throw new SoapException(ex.Message, SoapException.ClientFaultCode, "", ex); 
            }
        }
    }
}


Цитата(mr.DUDA @  3.3.2007,  18:30 Найти цитируемый пост)
Код клиента (веб-референс добавил под именем MyServiceProxy):

Если добавляешь веб-референс, то не нужно генерировать прокси wsdl-ом?
Я добавил веб-референс и клиент видит класс CommandResponse, но нет у него никаких методов.

Код

using MonitoringClient.localhost;

namespace MonitoringClient
{
    public partial class MainForm : Form
    {
        WebMonitoringService monitoringService;

        public MainForm()
        {
            InitializeComponent();
            monitoringService = new WebMonitoringService();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            StatusCommand statusCmd = (StatusCommand)monitoringService.createCommand("status");
            CommandResponse response = monitoringService.performCommand(statusCmd);
            ...
            ...
            ...
        }
}

Так вот у response нет никаких методов.  smile

Добавлено @ 17:18 
Цитата(neutrino @  5.3.2007,  16:06 Найти цитируемый пост)
Так вот у response нет никаких методов. 

Кроме этих:
Equals
GetHashCode
GetType
ToString


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neutrino
Дата 5.3.2007, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



У меня есть какая-то общая проблема с сериализацией: ни один класс уменя нормально не сериализируется - нет его содержимого на клиенте. Разве недостаточно пометить все эти классы атрибутом [Serialized]?

И для чего нужен, например, атрибут [XmlInclude]? Я им пометил абстрактный класс CommandBase:
Код

namespace core.commands
{
    /// <summary>
    /// Abstract base class for commands
    /// </summary>
    [Serializable]
    [XmlInclude(typeof(AddCommand))]
    [XmlInclude(typeof(RemoveCommand))]
    [XmlInclude(typeof(LoadURLXMLListCommand))]
    [XmlInclude(typeof(ListCommand))]
    [XmlInclude(typeof(SetCommand))]
    [XmlInclude(typeof(StartMonitoringCommand))]
    [XmlInclude(typeof(StopMonitoringCommand))]
    [XmlInclude(typeof(StatusCommand))]
    [XmlInclude(typeof(ClearCommand))]
    public abstract class CommandBase : ICommand
    {
        protected CommandResponse response;

        public CommandBase()
        {
        }

        #region ICommand Members

        public abstract bool execute(MonitoringEngine engine);

        CommandResponse ICommand.getResult()
        {
            return response;
        }
        
        /// <summary>
        /// Contains unique name for the command.
        /// </summary>
        public const string NAME = null;

        #endregion
    }
}


А потом каждую команду:
Код

namespace core.commands
{
    /// <summary>
    /// Command for appending new url to the list of urls for checking
    /// </summary>
    [Serializable]
    public class AddCommand : CommandBase
    {
        private string url;

        public AddCommand()
        {
        }

        public AddCommand(string url)
        {
            this.url = url;
        }

        public override bool execute(MonitoringEngine engine)
        {
            try
            {
                ArrayList checkers = engine.getCheckers();
                foreach (URLChecker checker in checkers)
                {
                    if (checker.URL == this.url)
                        throw new core.exceptions.URLAlreadyExistsException(this.url);
                }
                URLChecker newChecker = new URLChecker(url);
                engine.addChecker(newChecker);
            }
            catch (NotSupportedException)
            {
                return false;
            }

            this.response = new CommandResponse(true, null);
            return true;
        }
 
        public new const string NAME = "add";
    }
}


Добавлено @ 18:49 
Господи! Я ничего не понимаю!  smile 


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
mr.DUDA
Дата 5.3.2007, 23:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 2
Всего: 232



neutrino, смотри:

- класс веб-сервиса выставляет наружу методы и свойства -- эти методы и свойства доступны на клиенте
- класс веб-сервиса возвращает в методах некие return типы, каждый из которых должен быть полностью сериализуемым и не подразумевать дальнейший вызов серверных методов/свойств для получения их результата
- возвращаемые значения должны быть сериализуемыми типами
- в случае если заранее конкретный тип возвращаемого значения неизвестен, но наследует некий базовый тип (как у тебя в примере), то над базовым типом следует указать (с пом. XmlInclude для SOAP-сериализации) все типы наследуемые данным типом, чтобы десериализация прошла успешно; с точки зрения wsdl.exe, следует сгенерировать "распознаватель" типа по имени для всех указанных в XmlInclude типов.


--------------------
user posted image
PM MAIL WWW   Вверх
neutrino
Дата 8.3.2007, 00:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Цитата(mr.DUDA @  5.3.2007,  22:40 Найти цитируемый пост)
с точки зрения wsdl.exe, следует сгенерировать "распознаватель" типа по имени для всех указанных в XmlInclude типов. 

Как?
Я запускаю такую штуку: 
wsdl <хтмл-ссылка на веб-сервис>
Но вроде тот прокси, который так генерируется не нужен, если я добавляю веб-референс на сервис.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
mr.DUDA
Дата 8.3.2007, 11:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 2
Всего: 232



Вспомнил: для веб-сервисов надо юзать [SoapInclude] а не [XmlInclude]  smile 

Код
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Data;
 
public class Test : WebService {
   [WebMethod()]
   [return:XmlElement("MyTime", DataType="time")]
   public DateTime EchoString([XmlElement(DataType="string")] 
   string strval) {
        return DateTime.Now;
   }
 
   [WebMethod()]
   [SoapRpcMethod]
   [SoapInclude(typeof(Car)), SoapInclude(typeof(Bike))]
   public Vehicle Vehicle(string licenseNumber) {
      if (licenseNumber == "0") {
         Vehicle v = new Car();
         v.licenseNumber = licenseNumber;
         return v;
      }
      else if (licenseNumber == "1") {
          Vehicle v = new Bike();
          v.licenseNumber = licenseNumber;
          return v;
      }
      else {
         return null;
      }
   }
}
[XmlRoot("NewVehicle")] 
public abstract class Vehicle {
    public string licenseNumber;
    public DateTime make;
}
 
public class Car : Vehicle {
}
 
public class Bike : Vehicle {
}



--------------------
user posted image
PM MAIL WWW   Вверх
neutrino
Дата 10.3.2007, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Кхммм... Странно...

Если поменять все XmlInclude на SoapInclude, то вылетает какой-то Exception (Не просто какой-то, а который говорит, что нет аттрибутов XmlInclude или SoapInclude):
Код

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type core.commands.AddCommand was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write2_CommandBase(String n, String ns, CommandBase o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_CommandBase(Object o)
   at Microsoft.Xml.Serialization.GeneratedAssembly.CommandBaseSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()


Но если оставить XmlInclude, то сериализируется (сериализуется?) только название класса (в данном случае AddCommand):

Код

  <?xml version="1.0" encoding="utf-8" ?> 
  <CommandBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="AddCommand" xmlns="http://localhost:1034/WebSite1" /> 


Вот такой код:
Сервис:
Код

    [WebService(Namespace = "http://localhost:1034/WebSite1")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class WebMonitoringService : System.Web.Services.WebService
    {
        private MonitoringEngine monitoringEngine;
        private ServiceFacade serviceFacade;

        public WebMonitoringService()
        {
            this.monitoringEngine = new MonitoringEngine(5, 2000);
            this.serviceFacade = new ServiceFacade(this.monitoringEngine);
        }

        [WebMethod]
        [SoapInclude(typeof(AddCommand))]
        [SoapInclude(typeof(RemoveCommand))]
        [SoapInclude(typeof(LoadURLXMLListCommand))]
        [SoapInclude(typeof(ListCommand))]
        [SoapInclude(typeof(SetCommand))]
        [SoapInclude(typeof(StartMonitoringCommand))]
        [SoapInclude(typeof(StopMonitoringCommand))]
        [SoapInclude(typeof(StatusCommand))]
        [SoapInclude(typeof(ClearCommand))]
        public CommandBase createCommand(string commandLine)
        {
            int firstSpaceCharPosition = commandLine.IndexOf(' ');
            string command;
            string parameters;

            if (firstSpaceCharPosition == -1)
            {
                command = commandLine;
                parameters = "";
            }
            else
            {
                command = commandLine.Substring(0, firstSpaceCharPosition);
                parameters = commandLine.Substring(firstSpaceCharPosition + 1);
            }
            return (CommandBase)this.serviceFacade.createCommand(command, parameters);
        }
}


Класс CommandBase:
Код

namespace core.commands
{
    /// <summary>
    /// Abstract base class for commands
    /// </summary>
    [Serializable]
    [SoapInclude(typeof(AddCommand))]
    [SoapInclude(typeof(RemoveCommand))]
    [SoapInclude(typeof(LoadURLXMLListCommand))]
    [SoapInclude(typeof(ListCommand))]
    [SoapInclude(typeof(SetCommand))]
    [SoapInclude(typeof(StartMonitoringCommand))]
    [SoapInclude(typeof(StopMonitoringCommand))]
    [SoapInclude(typeof(StatusCommand))]
    [SoapInclude(typeof(ClearCommand))]
    public abstract class CommandBase : ICommand
    {
        protected CommandResponse response;

        public CommandBase()
        {
        }

        #region ICommand Members

        public abstract bool execute(MonitoringEngine engine);

        CommandResponse ICommand.getResult()
        {
            return response;
        }
        
        /// <summary>
        /// Contains unique name for the command.
        /// </summary>
        public const string NAME = null;

        #endregion
    }
}


И, например, AddCommand как в том примере:
Код

namespace core.commands
{
    /// <summary>
    /// Command for appending new url to the list of urls for checking
    /// </summary>
    [Serializable]
    public class AddCommand : CommandBase
    {
        private string url;

        public AddCommand()
        {
        }

        public AddCommand(string url)
        {
            this.url = url;
        }

        public override bool execute(MonitoringEngine engine)
        {
            try
            {
                ArrayList checkers = engine.getCheckers();
                foreach (URLChecker checker in checkers)
                {
                    if (checker.URL == this.url)
                        throw new core.exceptions.URLAlreadyExistsException(this.url);
                }
                URLChecker newChecker = new URLChecker(url);
                engine.addChecker(newChecker);
            }
            catch (NotSupportedException)
            {
                return false;
            }

            this.response = new CommandResponse(true, null);
            return true;
        }
 
        public new const string NAME = "add";
    }
}



--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
mr.DUDA
Дата 10.3.2007, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 2
Всего: 232



В примере из мсдн над веб-методом стоял ещё атрибут [SoapRpcMethod].

З.Ы. пойду учить матчасть  smile 


--------------------
user posted image
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
cully
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, cully, mr.DUDA, Exception.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Распределённые приложения и сеть | Следующая тема »


 




[ Время генерации скрипта: 0.0558 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.