#jquery #wcf #json #jsonp
#jquery #wcf #json #jsonp
Вопрос:
Цель: Предоставить простую службу WCF, которая принимала бы в качестве параметра строку, являющуюся именем пользователя, и посмотреть, существует ли она уже. Этот сервис будет использоваться на странице регистрации сайта, над которым я работаю, поэтому, когда пользователь вводит имя пользователя, он автоматически проверяет, было ли оно принято.
Я действительно заставил эту функциональность работать, но мне пришлось включить междоменное скриптирование для службы WCF. Мой вопрос «почему?»
К коду!
Моя служба WCF размещена на моем сайте MVC3 (изначально она была у меня на отдельном сайте, но, чтобы устранить все опасения по поводу межсайтового скриптирования, я переместил ее локально.)
Интерфейс для службы WCF
[ServiceContract]
public interface IMembershipServices
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
UriTemplate = "IsUsernameAvailable/{username}",
BodyStyle = WebMessageBodyStyle.Bare)]
MembershipUserAvailability IsUsernameAvailable(string username);
[OperationContract]
[WebGet(UriTemplate = "helloto/{name}", ResponseFormat = WebMessageFormat.Json)]
string Hello(string name);
}
Реализация:
[AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)]
public class MembershipServices : IMembershipServices
{
#region IMembershipServices Members
public string Hello(string name)
{
return String.Format("Hello:{0}", name);
}
public MembershipUserAvailability IsUsernameAvailable(string username)
{
if (String.IsNullOrWhiteSpace(username))
{
throw new ArgumentException(username);
}
MembershipUser membershipUser = Membership.GetUser(username, false);
var membershipUserAvailability = new MembershipUserAvailability
{
UserName = username,
IsAvailable = membershipUser == null ? true : false
};
return membershipUserAvailability;
}
#endregion
}
Web.config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<!-- This section is optional with the default configuration
model introduced in .NET Framework 4 -->
<service name="MedicalPracticeWeb.Services.MembershipServices" behaviorConfiguration="MembershipServicesBehaviors">
<!-- This endpoint is exposed at the base address provided by host: http://localhost/servicemodelsamples/service.svc -->
<endpoint address="" binding="webHttpBinding" bindingConfiguration="webHttpBindingJsonP" contract="MedicalPracticeWeb.Services.IMembershipServices" behaviorConfiguration="EndpBehavior" />
<!-- The mex endpoint is exposed at http://localhost/servicemodelsamples/service.svc/mex -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MembershipServicesBehaviors">
<!-- Add the following element to your service behavior configuration. -->
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingJsonP" crossDomainScriptAccessEnabled="true"></binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
Jquery to imlement call:
$(document).ready(function () {
var usernameTextbox = $('#username');
var usernameUnavailableRow = $('#usernameUnavailableRow');
var availabilityMessage = $('#availabilityMessage');
usernameTextbox.blur(function () {
if ($(this).val()) {
$.getJSON('/Services/MembershipServiceHost.svc/IsUsernameAvailable/' escape($(this).val()), function (results) {
if (results.IsAvailable) {
if (usernameUnavailableRow.is(':visible')) {
availabilityMessage.html('This username is available.');
availabilityMessage.addClass('usernameAvailable');
availabilityMessage.removeClass('usernameTaken');
}
}
else {
usernameUnavailableRow.show();
availabilityMessage.html('This username is already taken!');
availabilityMessage.addClass('usernameTaken');
availabilityMessage.removeClass('usernameAvailable');
}
});
}
});
});
Теперь все это отлично работает. Я могу ввести имя пользователя в текстовое поле моей регистрационной формы, и когда я покидаю поле, срабатывает событие onBlur и вызывает службу WCF, возвращающую ожидаемые результаты … но только в том случае, если у меня есть crossDomainScriptAccessEnabled = «true» в моем web.config. Это меня озадачивает. Возможно, это недостаток понимания JSON и JSONP (вполне возможно. Я довольно новичок в работе с JSON) но поскольку сервис размещен в том же домене, зачем мне этот набор?
Я взглянул на то, что отправлял Fiddler:
ПОЛУЧИТЬ /Services/MembershipServiceHost.svc/IsUsernameAvailable/Tim?callback=jQuery1510988704698288691_1302393437642amp;_= 1302393485350 HTTP/1.1
И есть параметр обратного вызова, который, как я вижу, упоминается в документах jQuery.
http://api.jquery.com/jQuery.getJSON/
Если URL-адрес содержит строку «обратный вызов =?» (или аналогичную, как определено серверным API), запрос вместо этого обрабатывается как JSONP. Смотрите обсуждение типа данных jsonp в $.ajax() для получения более подробной информации.
Означает ли это, что простое выполнение обратного вызова при успешном выполнении заставит getJSON использовать JSONP?
Приветствуется любой ввод.
Ответ №1:
Означает ли это, что простое выполнение обратного вызова при успешном выполнении заставит getJSON использовать JSONP?
Простой ответ — да.
Если вы добавите в параметр или зададите тип jsonp, jQuery автоматически, как по волшебству, выполнит всю тяжелую работу за вас. Вам также нужно, чтобы ваш сервис был достаточно умен, чтобы обернуть данные в вызов функции перед отправкой их вам — но .net делает это, если задан параметр.
На SO есть ряд других ответов, в которых рассказывается о том, как использовать jsonp через jQuery.