VSTO-specific web request not working (System.Net.WebException) - vsto

I wrote a 2013/2016 VSTO app for Microsoft Word using C#. My app creates a new toolbar with buttons. One such button runs my app, which launches a basic Windows Form.
Before the user can work with my app, they need to enter information like their license code and email address. My code in turns sends a basic request to my licensing server and awaits a response.
All my code has been running just fine and now it no longer is. Now, when I run the code, I receive the following two error messages:
System.Net.WebException: 'The underlying connection was closed: An
unexpected error occurred on a send.' Inner Exception: IOException:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host.
and
System.Net.WebException: 'The underlying connection was closed: An
unexpected error occurred on a send.' Inner Exception:
SocketException: An existing connection was forcibly closed by the
remote host
I decided to run the code using a standard console app to see if I received the same error message, and sure enough, it worked great! Now I am wondering if Word or the Microsoft VSTO technology is blocking my app from accessing my server.
Here is the code in VSTO that does not work
Note 1: Created a basic 2013/2016 C# VSTO add-in, added a toolbar, and added
Note 2: Added a reference to System.Web.
Note 3: Modified the website link and the query strings as I did not want to publish them on this public forum.
using System;
using Microsoft.Office.Tools.Ribbon;
using System.Web;
using System.Net;
namespace WordAddIn3
{
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
// Attempt to activate the product using the licensing server on the website.
Console.WriteLine("** ActivateLicense");
//build the url to call the website's software licensing component.
var builder = new UriBuilder("https://validwebsite.com");
builder.Port = -1;
//build the query string.
var query = HttpUtility.ParseQueryString(builder.Query);
query["license_key"] = "validactivationcdode";
query["product_id"] = "validproductid";
query["email"] = "validemailaddress";
builder.Query = query.ToString();
string url = builder.ToString();
Console.WriteLine("activation request:");
Console.WriteLine(url); //display the REST endpoint.
//make the synchronous call to the web service.
var syncClient = new WebClient();
var responseStream = syncClient.DownloadString(url);
Console.WriteLine("Response stream:");
Console.WriteLine(responseStream); //display the server json response.
}
}
}
Here is what is pretty much the same exact code in a console app that does work
Note 1: Created a basic C# console app.
Note 2: Added a reference to System.Web.
Note 3: Modified the website link and the query strings as I did not want to publish them on this public forum. You will receive an error, but that is due to the sample website not having a licensing server.
using System;
using System.Net;
using System.Web;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
// Attempt to activate the product using the licensing server on the website.
Console.WriteLine("** ActivateLicense");
//build the url to call the website's software licensing component.
var builder = new UriBuilder("https://validwebsite.com");
builder.Port = -1;
//build the query string.
var query = HttpUtility.ParseQueryString(builder.Query);
query["license_key"] = "validactivationcdode";
query["product_id"] = "validproductid";
query["email"] = "validemailaddress";
builder.Query = query.ToString();
string url = builder.ToString();
Console.WriteLine("activation request:");
Console.WriteLine(url); //display the REST endpoint.
//make the synchronous call to the web service.
var syncClient = new WebClient();
var responseStream = syncClient.DownloadString(url);
Console.WriteLine("Response stream:");
Console.WriteLine(responseStream); //display the server json response.
Console.ReadKey();
}
}
}
Can you help me determine why the code is no longer working in the add-in where it did before (with no code changes)?
I read a lot online and there seem to be too many reasons why this might happen. As an FYI, the website with the licensing server is running. It is (and always has been) a little slow, but when running the code with VSTO, the response is immediate (suggesting no timeout). The Console code runs and there is never a timeout.. I always get a response from the licensing server.
On another thread for a similar problem, someone recommended running WireShark. I am not really familiar with the product, but during my working console run, I received no error messages and instead I got messages like these:
Standard query 0x626a AAAA mywebsite.com
and
Standard query response 0x626a AAAA mywebsite.com
However, if I run the same code in VSTO, I get additional messages that are errors (this one shows up twice):
TCP 60 443 → 50308 [RST, ACK] Seq=1 Ack=125 Win=32768 Len=0

Related

Issue with SSH.NET UWP

I am having issues using SSh.net in a UWP App. This app will run on Win10.
I get the following error:
An attempt was made to access a socket in a way forbidden by its access permissions. I have looked online and there is no one actually dealing with this.The exact same code works in a standard Desktop App (WPF)
The key is the key string and I had to replace \r with \n because the PrivateKeyFile creation gave an error message and I tracked this down to carriage return placed instead of new line (by the textbox).
key = key.Replace("\r", "\n");
PrivateKeyFile(stringToStream(key));
client = new SshClient(ip, port, username, pkf);
if (!client.IsConnected)
{
try
{
client.Connect();
connected = true;
}
catch (Exception ex)
{
exception = ex.Message.ToString();
connected = false;
}
}
Finally resolved this issue - Look here: An attempt was made to access a socket in a way forbidden by its access permissions
Go down to the following line:
If you're getting the same error in Windows 8 development, it could be that you haven't enabled access over Private Networks in your Package.appxmanifest file:
Select the Private Networks (Client & Server) option as shown on the image.
Click here for the image

Android Emulator with Localhost ASP.Net Core API Calls

I've been trying to perform a GET request from Visual Studio's Android Emulator to an ASP.Net Core API running on localhost. I first read that I have to use IP 10.0.2.2 when performing the request from Android, so I have the following HTTP client code in my Android (Xamarin) App
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.Main);
var logInbutton = FindViewById<Button>(Resource.Id.logInButton);
logInbutton.Click += OnLogInButtonClicked;
}
private async void OnLogInButtonClicked(object sender, EventArgs e)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var uri = new Uri("http://10.0.2.2:5555/api/Orders?api-version=0.9");
var response = await client.GetAsync(uri);
}
}
However, each time I attempt to run this I'm greeted with a 400 Bad Request error. I know the request is okay since I can run the same Http client code from a console app without any errors. I then read that IIS express does not accept external requests and since the Android emulator is running in a VM this could be the reason.
So I then followed the advice on this SO post but was greeted with an Invalid URI: The hostname could not be parsed error. I'm not sure how to proceed from here. Is there a solution to the Invalid URI: The hostname could not be parsed error, or should I attempt to circumvent IIS Express and run solely with kestrel for development? Would even running solely in kestrel fix this problem?
I had a similar issue.
First, let's locate the correct applicationhost.config file.
You should check this location:
[solution folder]/.vs/config/applicationhost.config
Then people advice to set up binding like this:
<binding protocol="http" bindingInformation="*:5555:*" />
It did NOT work for me. I received "Invalid URI: The hostname could not be parsed".
What did work for me is the syntax like this:
<binding protocol="http" bindingInformation=":5555:" />
Please note, port 5555 is given as example. You should use the port your server is listening to.
I ran into the same issue when attempting to connect while running through kestrel. For me it worked using this configuration for the launchsettings:

Google OAuth 2.0 for desktop apps for Windows without Admin privileges

I've heard about Google's plan of modernizing OAuth interactions described here: https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html
Then I was looking at the sample desktop application for Windows found here: https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp.
It's pretty simple and it was working, but once I started Visual Studio without elevated privileges (as a non-admin), I experienced that the HttpListener was not able to start because of the following error: "Access Denied".
It turned out that starting an HttpListener at the loopback address (127.0.0.1) is not possible without admin rights. However trying localhost instead of 127.0.0.1 lead to success.
I found that there is a specific command that allows HttpListener to start at the given address (and port):
netsh http add urlacl url=http://+:80/MyUri user=DOMAIN\user
But it also can be only executed with admin rights, so it's not an option.
Still localhost seems to be the best shot but OAuth 2.0 for Mobile & Desktop Apps states the following regarding this section:
See the redirect_uri parameter definition for more information about the loopback IP address. It is also possible to use localhost in place of the loopback IP, but this may cause issues with client firewalls. Most, but not all, firewalls allow loopback communication.
This is why I'm a bit suspicious to use localhost. So I'm wondering what is the recommended way of Google in this case, as I'm not intending to run our application as administrator just for this reason.
Any ideas?
You can use TcpListener for instance instead of HttpListener. It does not need elevation to listen.
The following is a modified excerpt of this sample:
https://github.com/googlesamples/oauth-apps-for-windows/tree/master/OAuthDesktopApp
// Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";
// Creates a redirect URI using an available port on the loopback address.
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port);
output("redirect URI: " + redirectURI);
// Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
authorizationEndpoint,
System.Uri.EscapeDataString(redirectURI),
clientID,
state,
code_challenge,
code_challenge_method);
// Opens request in the browser.
System.Diagnostics.Process.Start(authorizationRequest);
// Waits for the OAuth authorization response.
var client = await listener.AcceptTcpClientAsync();
// Read response.
var response = ReadString(client);
// Brings this app back to the foreground.
this.Activate();
// Sends an HTTP response to the browser.
WriteStringAsync(client, "<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please close this window and return to the app.</body></html>").ContinueWith(t =>
{
client.Dispose();
listener.Stop();
Console.WriteLine("HTTP server stopped.");
});
// TODO: Check the response here to get the authorization code and verify the code challenge
The read and write methods being:
private string ReadString(TcpClient client)
{
var readBuffer = new byte[client.ReceiveBufferSize];
string fullServerReply = null;
using (var inStream = new MemoryStream())
{
var stream = client.GetStream();
while (stream.DataAvailable)
{
var numberOfBytesRead = stream.Read(readBuffer, 0, readBuffer.Length);
if (numberOfBytesRead <= 0)
break;
inStream.Write(readBuffer, 0, numberOfBytesRead);
}
fullServerReply = Encoding.UTF8.GetString(inStream.ToArray());
}
return fullServerReply;
}
private Task WriteStringAsync(TcpClient client, string str)
{
return Task.Run(() =>
{
using (var writer = new StreamWriter(client.GetStream(), Encoding.UTF8))
{
writer.Write("HTTP/1.0 200 OK");
writer.Write(Environment.NewLine);
writer.Write("Content-Type: text/html; charset=UTF-8");
writer.Write(Environment.NewLine);
writer.Write("Content-Length: " + str.Length);
writer.Write(Environment.NewLine);
writer.Write(Environment.NewLine);
writer.Write(str);
}
});
}
By default there is a URL pattern http://+:80/Temporary_Listen_Addresses/ which is allowed for all users (\Everyone)
You can use this as a prefix for your listener. More generally (to avoid collisions with other listeners) you should generate a URL under Temporary_Listen_Addresses (e.g. using a GUID) and use that as your listener prefix.
Unfortunately, a sysadmin can use netsh http to delete this entry or to restrict its usage to only certain users. Also, this does not appear to support listening for an HTTPS request as there is no corresponding ACL entry for port 443.
An admin can list all these permitted URL patterns using netsh http show urlacl as a command.

Bad CRC32 in GZIP stream

I am using DevForce 2010 and Silverlight 4.
When saving entities that contain large amount of binary data, I get this error:
Unhandled Error in Silverlight Application The remote server returned an error: NotFound.
When debuging the application I see these errors:
Unhandled Error in Silverlight Application Insufficient memory to continue the execution of the program.
Bad CRC32 in GZIP stream.
I found this thread on Ideablades forum that discusses the problem: http://www.ideablade.com/forum/forum_posts.asp?TID=3361&PN=1&title=bad-crc32-in-gzip-stream
Is this a problem on the server or client?
Is this a problem that has been resolved in any new version of DevForce 2010?
My server has 4 GB memory. Would increasing the memory resolve the problem?
Or what would be the right solution?
Yes, the OnEndpointCreated overrides on both client and server are where you should add the customization. You can add the following to remove GZIP from the binding:
public override void OnEndpointCreated(System.ServiceModel.Description.ServiceEndpoint endpoint)
{
if (endpoint.Binding is CustomBinding)
{
var binding = endpoint.Binding as CustomBinding;
var elements = binding.CreateBindingElements();
// Swap out existing (GZIP) message encoding for binary
var encoding = elements.Find<MessageEncodingBindingElement>();
if (encoding != null)
{
elements.Remove(encoding);
encoding = new BinaryMessageEncodingBindingElement();
elements.Insert(0, encoding);
endpoint.Binding = new CustomBinding(elements);
}
}
}
DevForce will find your classes if they're in an assembly probed on the client/server.
This will turn off compression for everything from your DevForce client to the EntityServer, so may be a bit heavy-handed. You can turn on IIS compression to compress data sent to the client to help.
There haven't been any changes to GZIP processing since the 6.1.7 release of DevForce 2010. That thread still contains the best information of how to work around the problem: 1) modify the save logic or your entity definition to reduce the amount of data saved; 2) turn off use of GZIP; or 3) write a custom message encoder with another compression library.
Thank you Kim Johnson,
I have looked at the samples and I feel uncomfortable adding those config files and maybe breaking something that works fine today.
If I go the code-way, will I be ably to switch off GZIP and still retain the rest of the default settings for DevForce?
I guess the code below is what I should go for?
If I save these classes on the client and server, will DevForce automatically find these classes?
//Client
using System.ServiceModel.Channels;
using IdeaBlade.Core.Wcf.Extensions;
public class ProxyEvents : IdeaBlade.EntityModel.ServiceProxyEvents {
public override void OnEndpointCreated(System.ServiceModel.Description.ServiceEndpoint endpoint) {
base.OnEndpointCreated(endpoint);
// My client code turning GZIP off comes here?
}
public override void OnFactoryCreated(System.ServiceModel.ChannelFactory factory) {
base.OnFactoryCreated(factory);
}
}
//Server
using System.ServiceModel.Channels;
using IdeaBlade.Core.Wcf.Extensions;
public class ServiceEvents : IdeaBlade.EntityModel.Server.ServiceHostEvents {
public override void OnEndpointCreated(System.ServiceModel.Description.ServiceEndpoint endpoint) {
base.OnEndpointCreated(endpoint);
// My server code turning GZIP off comes here?
}
public override void OnServiceHostCreated(System.ServiceModel.ServiceHost host) {
base.OnServiceHostCreated(host);
}
}

HTTP could not register URL (remote debugging)

C#, Windows 7.
I write an AutoCAD plugin and use the remote debuging (MS Visual Studio). My plugin must work as a WCF service. AutoCAD is unmanaged application and must to be as a host for my service. I am reading a book about WCF, and I try use it. I can't use acad.exe.config for my service settings: I have not permission. So I do it myself (I will read them from my xml file, but later, after refactoring). Code of my "server" (this code start by AutoCAD):
private static void RunServices() {
Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
try {
Uri address = new Uri("http://localhost:8000/CadService");
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "httpBinding";
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.Security.Mode = BasicHttpSecurityMode.None;
host = new ServiceHost(typeof(CadService));
host.AddServiceEndpoint(typeof(ICadService), binding, address);
host.Open(); // I get an Exception here...
if (doc != null) {
doc.Editor.WriteMessage("Service launched.\n");
}
}
catch (Exception ex) {
if (doc != null) {
doc.Editor.WriteMessage("Exception: {0}\n", ex.Message);
}
}
}
I get an exception (look the code comment):
Exception: HTTP could not register URL http://+:8000/CadServices/.
Your process does not have access rights to this namespace
(see http://go.microsoft.com/fwlink/?LinkId=70353 for details).
But the http://go.microsoft.com/fwlink/?LinkId=70353 page is not exist. I try launch MS Visual Studio 2013 as admin (I read about this here), but It is not help me (look P.S.2 bellow).
P.S. If I launch AutoCAD as admin - all works fine.
P.S.2 If I launch the remote debugger as admin - all works fine too.
But I need use it as a usual user. Can I start my service (hosted in the AutoCAD) without the admin rights?
This is probably because AutoCad does not have the required rights to register the port in HTTP.SYS. In that case you have two options:
Start Autocad in Admin mode
Register the port / endpoint in HTTP.SYS manually. For this, there are several tools available. This is the one I would use : http://www.codeproject.com/Articles/437733/Demystify-http-sys-with-HttpSysManager
Let me know if this works