简体   繁体   English

webapi odata更新savechanges问题-无法连接到远程服务器

[英]webapi odata update savechanges issue - Unable to connect to remote server

In my mvc webapplication, I am using webapi to connect to my database through odata. 在我的mvc Web应用程序中,我正在使用webapi通过odata连接到我的数据库。

Both MVC WebApp and Odata WebApi are on different ports of Azure cloud service webrole endpoints. MVC WebApp和Odata WebApi都位于Azure云服务webrole终结点的不同端口上。

MVC WebApp - 80
Odata WebApi - 23900

When I do a odataproxy updateobject and call savechanges like 当我做一个odataproxy updateobject并调用savechanges像

odataProxy.UpdateObject(xxx);
odataProxy.SaveChanges(System.Data.Services.Client.SaveChangesOptions.PatchOnUpdate);

I am getting a weird exception on savechanges method call - unable to connect to remote server. 我在savechanges方法调用上遇到一个奇怪的异常-无法连接到远程服务器。

When I tried to look into inner exceptions, It says that - No connection could be made as the target machine actively refused it 127.0.0.1: 23901 当我试图寻找到内心的例外,它说-无连接可以作出,因为目标机器积极地拒绝它127.0.0.1:23901

So if you observe the port number in the exception, it shows as 23901 and obviously this error should come as the request is supposed to hit 23900. 因此,如果您观察到异常中的端口号,它将显示为23901,并且显然应该出现此错误,因为请求应该达到23900。

I am facing this exception only when running on azure cloud solution. 我仅在Azure云解决方案上运行时才遇到此异常。 Whenever I do an update request, it fails by hitting a wrong port (added by 1). 每当我执行更新请求时,它都会通过命中错误的端口(加1)失败。

Another thing is, apart from this updateobject -> savechanges, rest all works like fetching data and adding data. 另一件事是,除了此updateobject-> savechanges之外,其余所有工作都如获取数据和添加数据一样。

FWIW, I've just run across this same thing. FWIW,我碰到过同样的事情。 Darn near annoying and I really hope it doesn't happen in production. 该死的烦人,我真的希望它不会在生产中发生。 I'm surprised no other people have come across this though. 我很惊讶,但是没有其他人遇到过这个问题。

The idea of creating a new context, attaching the object(s) and calling SaveChanges really repulsed me because not only does it practically break all forms of testing, it causes debug code and production code to be fundamentally different. 创建新上下文,附加对象并调用SaveChanges的想法真的使我感到反感,因为它不仅实际上破坏了所有形式的测试,而且使调试代码和生产代码根本不同。

I was however able to work around this problem in another way, by intercepting the request just before it goes out and using reflection to poke at some private fields in memory to "fix" the port number. 但是,我能够以另一种方式解决此问题,方法是在请求发出之前拦截该请求,并使用反射来戳入内存中的某些专用字段以“修复”端口号。

UPDATE: It's actually easier than this. 更新:实际上比这容易。 We can intercept the request generation process with the BuildingRequest event. 我们可以使用BuildingRequest事件来拦截请求生成过程。 It goes something like this: 它是这样的:

var context = new Context(baseUri);

context.BuildingRequest += (o, e) =>
{
    FixPort(e);
};

Then the FixPort method just needs to test the port number and build a new Uri, attaching it back to the event args. 然后, FixPort方法仅需要测试端口号并构建一个新的Uri,并将其附加到事件args。

[Conditional("DEBUG")]
private static void FixPort(BuildingRequestEventArgs eventArgs)
{
    int localPort = int.Parse(LOCAL_PORT);

    if (eventArgs.RequestUri.Port != localPort)
    {
        var builder = new UriBuilder(eventArgs.RequestUri);
        builder.Port = localPort;

        eventArgs.RequestUri = builder.Uri;
    }
}

Here's the original method using reflection and SendingRequest2 , in case anyone is still interested. 这是使用反射和SendingRequest2的原始方法,以防万一仍然有人感兴趣。

First we create a context and attach a handler to the SendingRequest2 event: 首先,我们创建一个上下文并将处理程序附加到SendingRequest2事件:

var context = new Context(baseUri);

context.SendingRequest2 += (o, e) =>
{
    FixPort(e.RequestMessage);
};

The FixPort method then handles rewriting the URL of the internal request, where LOCAL_PORT is the port you expect, in your case 23900: 然后, FixPort方法处理重写内部请求的URL,其中LOCAL_PORT是您期望的端口,在您的情况下为23900:

[Conditional("DEBUG")]
private static void FixPort(IODataRequestMessage requestMessage)
{
    var httpWebRequestMessage = requestMessage as HttpWebRequestMessage;
    if (httpWebRequestMessage == null) return;

    int localPort = int.Parse(LOCAL_PORT);

    if (httpWebRequestMessage.HttpWebRequest.RequestUri.Port != localPort)
    {
        var builder = new UriBuilder(requestMessage.Url);
        builder.Port = localPort;

        var uriField = typeof (HttpWebRequest).GetField("_Uri",
            BindingFlags.Instance | BindingFlags.NonPublic);
        uriField.SetValue(httpWebRequestMessage.HttpWebRequest, builder.Uri);
    }
}

I have found the root cause and a temporary workaround. 我已经找到根本原因和临时解决方法。

Cause: When you hit WebApi through some port :23900 in Azure compute emulator and do an update or delete operation, somehow the last request is blocking the port and because of the port walking feature in Azure emulator, it is jumping to next port where there is no service available which is causing the issue. 原因:当您通过Azure计算模拟器中的某个端口:23900命中WebApi并执行更新或删除操作时,上一个请求由于某种原因阻塞了该端口,并且由于Azure模拟器中的端口漫游功能,它跳到了那里的下一个端口没有导致问题的服务。

Even this issue is found only in development emulators. 即使在开发仿真器中也找不到此问题。

Temp Workaround: Use a different proxy to attach to updated context object and then save from the other proxy object. 临时解决方法:使用其他代理附加到更新的上下文对象,然后从另一个代理对象保存。

var odataProxy1 = xxx;
var obj = odataProxy1.xyz.FirstOrDefault();
obj.property1="abcd";
...//Other update assignments

var odataProxy2 = xxx;
odataProxy2.AttachTo("objEntitySet",obj);
odataProxy2.UpdateObject(obj)
odataProxy2.SaveChanges(ReplaceOrUpdate);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM