我有两个项目,一个是WCF服务,它在文本框中说出文本/句子.
public class Service1 : IService1
{
public string RunTts(string text)
{
using (SpeechSynthesizer synth = new SpeechSynthesizer())
{
// Configure the audio output.
synth.SetOutputToDefaultAudioDevice();
synth.Speak(text);
return "";
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在第二个项目的_Layout.cshtml页面中用ajax调用它,它是asp.net mvc.
<script type="text/javascript">
function ttsFunction() {
serviceUrl = "Service1.svc/RunTts";
$.ajax({
type: "POST",
url: serviceUrl,
data: '{"text": "' + $('#speak').val() + '"}',
contentType: "text/xml; charset=utf-8",
dataType: "text/xml",
error: function (xhr,status,error) {
console.log("Status: " + status); // got "error"
console.log("Error: " + error); // got "Not Found"
console.log("xhr: " + xhr.readyState); // got "4"
},
statusCode: {
404: function() {
console.log("page not found"); // got
}
}
});
}
</script>
Run Code Online (Sandbox Code Playgroud)
因为我收到404错误,所以我觉得网址错了.请参阅文件的结构,我猜这个Web引用叫做'ServiceReference1'.
如屏幕截图所示,该服务未托管在您的Web应用程序中.您无法直接从客户端访问此类服务(在Web应用程序之外托管),因为您违反了相同的原始策略限制.它是信任的基本概念之一,Web安全基于此(例如保护aganist XSS) - 您无法发送跨域AJAX请求.这基本上表明,如果来自一个站点(例如https://bank.ny.com
)的内容被授予访问系统上的资源的权限,那么来自该站点的任何内容将共享这些权限,而来自另一个站点(https://nsa.ny.com
)的内容将必须单独授予权限(通常,术语起源 使用域名,应用程序层协议和端口号定义.
不过,您至少有4种解决方案可以解决您的问题:
首先 - 通过中间控制器层与您的服务对话.这样做意味着生成代理类(通过svcutil.exe,通过使用Visual Studio添加服务引用所做的工作).与此客户端的通信如下所示:
public class TtsController
{
public JsonResult RunTts(string text)
{
using(var client = new ServiceReference1.Service1Client())
{
var response = client.RunTts(text);
return Json(response);
...
Run Code Online (Sandbox Code Playgroud)
然后JavaScript端应该使用这样的URL :( var serviceUrl = "/Tts/RunTts"
以及传递给AJAX请求的正确JSON数据,我将进一步讨论).
第二 - 直接与服务对话.如果要直接与服务通信,则必须在Web应用程序中托管此服务.应遵循正确的WCF配置以支持RESTful服务:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webby">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Namespace.Service1">
<endpoint address=""
behaviorConfiguration="webby"
binding="webHttpBinding"
contract="Namespace.IService1" />
</service>
</services>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)
对于RESTful端点,您应该使用的绑定WebHttpBinding
以及适当的行为.另外,许多RESTful服务都有免配置的体验 - WebServiceHostFactory
.您的.svc文件应如下所示(MSDN):
<%@ ServiceHost Language="C#" Debug="true" Service="Namespace.Service1"
CodeBehind="Service1.svc.cs"
Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
Run Code Online (Sandbox Code Playgroud)
WebServiceHostFactory
创建一个实例WebServiceHost
,并且由于WebServiceHost
将使用WebHttpBinding
和相关行为自动配置端点,因此根本不需要在web.config中对此端点进行任何配置(当然,如果您需要自定义绑定,你必须使用配置)(MSDN).
然后访问该服务使用适当的完整URL:http://localhost:[port]/Service1.svc/RunTts
或相对的一个:/Service1.svc/RunTts
.
由于您正在使用ASP.NET MVC,根据您的路由定义,请求将被分派到某个控制器,此类操作不存在.你必须告诉MVC忽略你的服务路由:
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
Run Code Online (Sandbox Code Playgroud)
(顺便说一句:如果您将.svc文件放在应用程序的不同目录下,请分别修改URL和路由以忽略.)
您的代码需要一些额外的修复:
如果要以JSON格式发送消息,请正确指定dataType
和contentType
参数:
$.ajax({
url: serviceUrl,
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
...
Run Code Online (Sandbox Code Playgroud)不要手动构造JSON字符串,因为它可能导致进一步的解析错误 - 使用转换器,例如:
var data = new Object();
data.text = $('#speak').val();
var jsonString = JSON.stringify(data);
$.ajax({
...
data: jsonString,
...
Run Code Online (Sandbox Code Playgroud)为您的服务提供其他声明性信息:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
string RunTts(string text);
...
Run Code Online (Sandbox Code Playgroud)从项目中删除服务引用.你不需要它,因为这里没有使用中间控制器.
第三 - JSONP(在此处和此处查看)可用于克服原始策略限制.但是你不能使用JSONP进行POST,因为它不会那样工作 - 它创建了一个<script>
获取数据的元素,这必须通过GET请求来完成.JSONP解决方案不使用XmlHttpRequest
对象,因此它不是标准理解方式的AJAX请求,但内容仍然是动态访问的 - 对最终用户没有区别.
$.ajax({
url: serviceUrl,
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
data: data,
...
[OperationContract]
[WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate="RunTts?text={text}")]
public string RunTts(string text);
Run Code Online (Sandbox Code Playgroud)
允许跨域请求的RESTful WCF配置:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="jsonp" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webby">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Namespace.Service1">
<endpoint address=""
behaviorConfiguration="webby"
binding="webHttpBinding"
bindingConfiguration="jsonp"
contract="Namespace.IService1" />
</service>
</services>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)
第四 - CORS.在现代浏览器中实现,替代 JSON和Padding.
归档时间: |
|
查看次数: |
2403 次 |
最近记录: |