Вызов .NET сервиса (WCF RESTful) из Android приложения

    Привет Хаброжители!

    Вот недавно столкнулся с проблемой, нужно было вызвать .NET WCF сервис из Javа. Нашел несколько примеров, реализации, одним из них и хочу поделиться, вдруг пригодиться кому. Прогулявшись по просторам интернета, нашел готовое решение для SOAP сервисов. Разбираться с ним не стал и продолжил поиск. Затем, было найдено решение с использованием WCF RESTful сервиса, который возвращал данные в формате JSON. Решил разобраться подробнее и попробовать как это работает.



    Итак, для начала нам надо написать WCF RESTful [EN] сервис. Для начала определим дата-контракт:
    Message.cs

    using System.Runtime.Serialization;
    
    namespace TestService
    {
    	[DataContract]
    	public class Message
    	{
    		[DataMember(Order = 1)]
    		public string Header { get; set; }
    
    		[DataMember(Order =2)]
    		public string Body { get; set; }
    	}
    }

    Задаем порядок элементов, которые будет возвращать веб-сервис посредством Order = x.
    Потом определим сервис-контракт:
    ITestService.cs

    using System.ServiceModel;
    using System.ServiceModel.Web;
    
    namespace TestService
    {
    	[ServiceContract]
    	public interface ITestService
    	{
    		[OperationContract]
    		[WebGet(UriTemplate = "/GetMessage/?header={header}&?body={body}", ResponseFormat = WebMessageFormat.Json)]
    		Message ComposeMessage(string header, string body);
    	}
    }
    

    Подробнее о UriTemplate можете почитать тут.
    Реализуем сервис:
    TestService.svc.cs

    using System.ServiceModel.Activation;
    
    namespace TestService
    {
    	public class TestService : ITestService
    	{
    		#region ITestService Members
    
    		public Message ComposeMessage(string header, string body)
    		{
    			Message message = new Message() { Header = header, Body = body };
    
    			return message;
    		}
    
    		#endregion
    	}
    }
    

    И конечно же конфигурация сервиса:
    web.config

    <?xml version="1.0"?>
    <configuration>
    	<system.web>
    		<compilation debug="true" targetFramework="4.0" />
    	</system.web>
    	<system.serviceModel>
    		<services>
    			<service name="TestService.TestService">
    				<endpoint binding="webHttpBinding" contract="TestService.ITestService" behaviorConfiguration="webHttp"/>
    			</service>
    		</services>
    		<behaviors>
    			<endpointBehaviors>
    				<behavior name="webHttp">
    					<webHttp helpEnabled="true"/>
    				</behavior>
    			</endpointBehaviors>
    			<serviceBehaviors>
    				<behavior>
    					<serviceMetadata httpGetEnabled="true"/>
    				</behavior>
    			</serviceBehaviors>
    		</behaviors>
    	</system.serviceModel>
    	<system.webServer>
    		<modules runAllManagedModulesForAllRequests="true"/>
    	</system.webServer>
    </configuration>
    

    Размещать сервис мы будем в IIS(это можно сделать либо в Visual Studio либо через Диспетчер служб IIS). Создадим виртуальный каталог, назовем его TestService.
    В случае размещения внутри служб IIS, управляемого WCF, среде WCF обычно требуется файл .svc, указывающий на тип службы, а также записи в файле web.config, информирующие WCF о конечной точке (привязке и поведениях среди прочих параметров настройки).

    И последний штрих:
    TestService.svc

    <%@ ServiceHost Language="C#" Debug="true" Service="TestService.TestService" CodeBehind="TestService.svc.cs" %>

    После всех действий наш виртуальный каталог должен иметь примерно следующее содержимое:

    В bin фолдере должна лежать *.dll с сервисом.
    Все наш сервис готов. Для того чтобы протестировать полученный результат, в адресной строке браузера наберем
    localhost/TestService/TestService.svc/GetMessage/?header=Hello&?body=World
    Результат должен выглядеть так:
    {«Header»:«Hello»,«Body»:«World»}
    Это и есть JSON Response.
    Перейдем наконец-то к нашему Android приложению.
    Советую перечитать этот пост. Из него позаимствуем реализацию AsyncTask.
    Публикация всего кода не имеет смысла, поэтому «вырежем» от туда только метод который и будет разбирать JSON ответ, пришедший от сервиса. Вот его код:
    private String getMessage(String header, String body) {
    		HttpClient httpclient = new DefaultHttpClient();
    		HttpGet httpget = new HttpGet(_resources.getString(R.string.serviceAddress) + "/GetMessage/?header="+ header + "&?body=" + body);
    
    		HttpResponse response;
    		try {
    			response = httpclient.execute(httpget);
    
    			HttpEntity entity = response.getEntity();
    
    			if (entity != null) {
    				InputStream instream = entity.getContent();
    				String result = convertStreamToString(instream);
    				JSONObject json = new JSONObject(result);
    
    				// Parsing
    				JSONArray nameArray = json.names();
    				JSONArray valArray = json.toJSONArray(nameArray);
    
    				_getResponse = nameArray.getString(0) + "="
    						+ valArray.getString(0) + ", " + nameArray.getString(1)
    						+ "=" + valArray.getString(1);
    
    				instream.close();
    			}
    
    		} catch (Exception e) {
    			_getResponse = e.getMessage();
    		}
    
    		return _getResponse;
    	}
    

    Адрес сервиса _serviceAddress будет иметь вид:
    10.0.2.2/TestService/TestService.svc
    поскольку, при обращении к localhost, мы получим Connection Refused IOException(кому интересно, подробнее читаем тут).
    Также в файл AndroidManifest.xml надо добавить uses-permission для того чтобы приложение могло вызвать веб-сервис:
    <uses-permission android:name="android.permission.INTERNET" />

    Вот в принципе и все что я хотел рассказать…

    Исходники:
    Лежат тут.

    Полезные ссылки:
    Всем спасибо за внимание!
    Поделиться публикацией

    Похожие публикации

    Комментарии 13

      –5
      REST в WCF — обнять и плакать.
        +5
        В последнем проекте использовали REST в WCF, при чем изначально использовались soap, и надо сказать что WCF очень хорошо поддерживает REST — вплоть до генерации документов по интерфейсу методов — а так как изначально использовали WCF — переход c SOAP на REST обошелся очень дешево (с учетом передаваемых типов объектов — в 20 методах отдельные объекты с 10-40 свойствами на вход и выход) — изменения заключались в дописывании нескольких строчек в конфиг-файле и в прописывании указанных заказчиком адресов в методах + для нескольких объектов переопределили имя тега в генерируемом XML — в течении дня привели в нужный заказчику формат.

        Для приемочных тестов, конечно же, нельзя сгенерировать прокси как для SOAP. Но имея на руках объекты из которых сериализуется XML в WCF REST можно дешево получить прокси — без ручной десериализации.
          –2
          Content Negotiation WCF умеет?
            +3
            Да, умеет. И в полезных ссылках даже можно посмотреть, как это делается.
            0
            боюсь спросить, что вы имеете ввиду под REST сервисом?
              0
              WCF это даже больше чем REST-веб сервис…
                0
                Полностью согласен — но мой коммент был к комментарию >REST в WCF — обнять и плакать."
                  –1
                  это я как бы ваш подытожил
            +1
            Ох ваш бы топик, да на месяц пораньше =) Кучу времени потратил на поиск информации на эту тему.
            Все равно спасибо!
              +3
              могу порекомендовать обратить внимание на новый WCF Web API, который разрабатывается при участии Глена Блока (автор MEF). Очень положительные отзывы и очень перспективный проект, который уже стабилен и годен для применения

              wcf.codeplex.com/

              и материалы по нему
              codebetter.com/glennblock/2011/03/07/wcf-web-apis-roundupvolume-2/
                0
                -> И последний штрих:

                Можно заменить, на дополнительные строчки в web.config

                <serviceHostingEnvironment multipleSiteBindingsEnabled="true">
                <clear/>
                <serviceActivations>
                <add service="TestService.TestService" relativeAddress="TestService.svc"/>
                </serviceActivations>
                </serviceHostingEnvironment>
                  0
                  Если сервис хостить в IIS, то *.svc должен быть, его так не заменить.
                  0
                  Автор, большое спасибо за пост.

                  В дополнение. В моем случае добавлять IIS в зависимости проекта было совершенно ни к чему. Без IIS оно поднимается достаточно просто:

                  WebServiceHost host = new WebServiceHost(typeof(TestService), new Uri(endPoinUri));
                  host.Open()

                  Это полезно когда требуются локальные пойнты, поддерживающие определенное Rest API. Засовываем этот вызов в Windows-службу и все.

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое