четверг, мая 31, 2012

Ускорение работы WCF-сервиса

Вчера были тестовые запуски сервиса, хостящегося (теперь) на IIS. Один вызов занимал 30 секунд (или около того). От великого огорчения стал внимательно читать документацию.

Вычитал, что WCF при отсутствии частно-определённой привязки сначала лезет исследовать прокси-серверы в сети. Никаких таких устройств у нас нет, потому до таймаута сервис просто "ждал".

Но стоило определить свою привязку как дело пошло. 4 строчки в конфиге дали ускорение работы в несколько сотен тысяч раз.

А всё из-за этого: usedefaultwebproxy="false"

понедельник, мая 28, 2012

Как передать массив из Android в WCF?

Ну, то что из Android практически невозможно передать сложный тип веб-сервису на WCF, понятно. Ведь кроме Microsoft для Microsoft ничего не существует. Тут даже и вопросов никаких не возникает: "так надо". А вот почему нужны такие пляски с бубнами для передачи простого массива из приложения на Android в WCF-сервис, непонятно. Этот ваш любимый ksoap2 тоже не особо-то помогает в виде "из коробки". Приходится смотреть логи, сравнивать сообщения и подстраиваться. А что, замечательный способ разработки. Если некуда спешить.

Короче.

Полностью завершённый код C#, делающий то, что нужно
class Program
{
 static void Main(string[] args)
 {
  ServiceReference1.ServiceClient sr = new ServiceReference1.ServiceClien();
  sr.GetSomething(new []{10, 20, 30});
  sr.Close();
 }
}
Вызывает и работает.

Теперь то же самое из Android. Просто так передать массив не получится, его надо передавать изощрённо (извращённо?). Потому что в противном случае WCF не сможет десериализовать сообщение.

Делай раз
1. Сделать вид, что передаём не какой-то там паршивый int[], но настоящий Объект! настоящего Класса! Со всеми атрибутами такого. А именно
2. Полный код "взрослого класса"
public class MyIds extends Vector implements KvmSerializable {
    private static final long serialVersionUID = -1143242342342342265L;

    @Override
    public Object getProperty(int i) {
        return this.get(i);
    }
    @Override
    public int getPropertyCount() {
        return this.size();
    }
    @Override
    public void setProperty(int i, Object o) {
        this.add(Integer.parseInt(o.toString()));
    }
    @Override
    public void getPropertyInfo(int i, Hashtable hashtable, PropertyInfo propertyInfo) {
        propertyInfo.name = "int";
        propertyInfo.namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";        propertyInfo.type = PropertyInfo.INTEGER_CLASS;
    }
}

Самый цимес в жирной строчке. Хотите неприятно провести время - уберите её.

После этого вызов метода GetSomething в Android становится очень простым
3. public static int getSomething(int[] args)
    {
        final String MethodName = "GetSomething";
        final String SoapAction = "http://mydomain.ru/MyService/IInterface/GetSomething";
        SoapObject req = new SoapObject(Namespace, MethodName);

        MyIds myIds = new MyIds();
        for(Integer i : args)
            myIds.add(i);
       
        PropertyInfo pi = new PropertyInfo();
        pi.setName("WCFParam");
        pi.setValue(myIds);
        pi.setType(myIds.getClass());
        req.addProperty(pi);
        SoapSerializationEnvelope se = getEnvelope(req);
        SoapPrimitive p = initializeTransportAndCall(SoapAction, se);

        if (null == p)
            return 0;

        return Integer.parseInt(p.toString());
    }
Всё. WCF SOAP WS принимает массив целых чисел. Ну и дальше дело техники.