'System.InvalidOperationException' when LINQ to SQL using WCF on WP8 - c#

This is the code where the exception occurs:
public Listado()
{
InitializeComponent();
ListadoWebService();
}
public void ListadoWebService()
{
// InitializeComponent();
ServiceTours.ServiceToursClient cl = new ServiceTours.ServiceToursClient();
cl.ListadoCompleted += new EventHandler<ListadoCompletedEventArgs>(Listado2);
cl.ListadoAsync();
}
private void Listado2(object sender, ListadoCompletedEventArgs e)
{
listB.ItemsSource = e.Result; // listB is ListBox in WP8
}
I get following Exception:
An exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.ni.dll but was not handled in user code
I would like to say that I directly followed this tutorial on MSDN
So the final Service Reference url is: http://IP/WcfTours/ServiceTours.svc as it should be. //99.99.99 represents IP
World Wide Web Services (HTTP) in Allow an app through Windows Firewall is allowed for domain public and private.
Virtual Directory is created.
Will somebody please help me with setting the endpoint please ?
Exception message:
{System.InvalidOperationException: An endpoint configuration section for contract 'ServiceTours.IServiceTours' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.
at System.ServiceModel.Description.ConfigLoader.LookupChannel(String configurationName, String contractName, Boolean wildcard)
at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
at System.ServiceModel.ChannelFactory1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)
at System.ServiceModel.EndpointTrait1.CreateSimplexFactory()
at System.ServiceModel.ClientBase1.CreateChannelFactoryRef(EndpointTrait1 endpointTrait)
at System.ServiceModel.ClientBase1.InitializeChannelFactoryRef()
at System.ServiceModel.ClientBase1..ctor()
at PhoneApp1.ServiceTours.ServiceToursClient..ctor()
at PhoneApp1.Listado.ListadoWebService()
at PhoneApp1.Listado..ctor()}

As soon as you add a Web Service reference in your project a new ServiceReferences.ClientConfig file is created in the root folder of your project. Open it somewhere and look for:
<client>
<endpoint .... name="endpointName" />
<endpoint .... name="endpointName2" />
</client>
In your case you have more than one records there. so select the appropriate and pass the name into contructor of ServiceToursClient.
new ServiceToursClient("endpointName")

Related

Apache.NMS.NMSConnectionException: 'Error connecting to activemqhost:61616.'

I have the console project in .NET Framework 4.7.2 which installed Apache.NMS and Apache.NMS.ActiveMQ packages. I copy and paste the sample code from official documentation and when I run it, it hits error Apache.NMS.NMSConnectionException: 'Error connecting to activemqhost:61616.' SocketException
This is my code:
class Program
{
public static void Main(string[] args)
{
// Example connection strings:
// activemq:tcp://activemqhost:61616
// stomp:tcp://activemqhost:61613
// ems:tcp://tibcohost:7222
// msmq://localhost
Uri connecturi = new Uri("activemq:tcp://activemqhost:61616");
Console.WriteLine("About to connect to " + connecturi);
// NOTE: ensure the nmsprovider-activemq.config file exists in the executable folder.
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
using (IConnection connection = factory.CreateConnection())
{
}
}
}
Below is from my activemq.xml
<transportConnectors>
<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
Solved after I used this connectionstring Uri connecturi = new Uri("tcp://localhost:61616");

C# - How to set a Service Ref. Client Endpoint [duplicate]

I'd like to programmatically modify my app.config file to set which service file endpoint should be used. What is the best way to do this at runtime? For reference:
<endpoint address="http://mydomain/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
contract="ASRService.IASRService" name="WSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
Is this on the client side of things??
If so, you need to create an instance of WsHttpBinding, and an EndpointAddress, and then pass those two to the proxy client constructor that takes these two as parameters.
// using System.ServiceModel;
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("http://localhost:9000/MyService"));
MyServiceClient client = new MyServiceClient(binding, endpoint);
If it's on the server side of things, you'll need to programmatically create your own instance of ServiceHost, and add the appropriate service endpoints to it.
ServiceHost svcHost = new ServiceHost(typeof(MyService), null);
svcHost.AddServiceEndpoint(typeof(IMyService),
new WSHttpBinding(),
"http://localhost:9000/MyService");
Of course you can have multiple of those service endpoints added to your service host. Once you're done, you need to open the service host by calling the .Open() method.
If you want to be able to dynamically - at runtime - pick which configuration to use, you could define multiple configurations, each with a unique name, and then call the appropriate constructor (for your service host, or your proxy client) with the configuration name you wish to use.
E.g. you could easily have:
<endpoint address="http://mydomain/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
contract="ASRService.IASRService"
name="WSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="https://mydomain/MyService2.svc"
binding="wsHttpBinding" bindingConfiguration="SecureHttpBinding_IASRService"
contract="ASRService.IASRService"
name="SecureWSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://mydomain/MyService3.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IASRService"
contract="ASRService.IASRService"
name="NetTcpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
(three different names, different parameters by specifying different bindingConfigurations) and then just pick the right one to instantiate your server (or client proxy).
But in both cases - server and client - you have to pick before actually creating the service host or the proxy client. Once created, these are immutable - you cannot tweak them once they're up and running.
Marc
I use the following code to change the endpoint address in the App.Config file. You may want to modify or remove the namespace before usage.
using System;
using System.Xml;
using System.Configuration;
using System.Reflection;
//...
namespace Glenlough.Generations.SupervisorII
{
public class ConfigSettings
{
private static string NodePath = "//system.serviceModel//client//endpoint";
private ConfigSettings() { }
public static string GetEndpointAddress()
{
return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
}
public static void SaveEndpointAddress(string endpointAddress)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNode node = doc.SelectSingleNode(NodePath);
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(getConfigFilePath());
}
catch( Exception e )
{
throw e;
}
}
public static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(getConfigFilePath());
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
}
}
SomeServiceClient client = new SomeServiceClient();
var endpointAddress = client.Endpoint.Address; //gets the default endpoint address
EndpointAddressBuilder newEndpointAddress = new EndpointAddressBuilder(endpointAddress);
newEndpointAddress.Uri = new Uri("net.tcp://serverName:8000/SomeServiceName/");
client = new SomeServiceClient("EndpointConfigurationName", newEndpointAddress.ToEndpointAddress());
I did it like this. The good thing is it still picks up the rest of your endpoint binding settings from the config and just replaces the URI.
this short code worked for me:
Configuration wConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);
ClientSection wClientSection = wServiceSection.Client;
wClientSection.Endpoints[0].Address = <your address>;
wConfig.Save();
Of course you have to create the ServiceClient proxy AFTER the config has changed.
You also need to reference the System.Configuration and System.ServiceModel assemblies to make this work.
Cheers
This is the shortest code that you can use to update the app config file even if don't have a config section defined:
void UpdateAppConfig(string param)
{
var doc = new XmlDocument();
doc.Load("YourExeName.exe.config");
XmlNodeList endpoints = doc.GetElementsByTagName("endpoint");
foreach (XmlNode item in endpoints)
{
var adressAttribute = item.Attributes["address"];
if (!ReferenceEquals(null, adressAttribute))
{
adressAttribute.Value = string.Format("http://mydomain/{0}", param);
}
}
doc.Save("YourExeName.exe.config");
}
I have modified and extended Malcolm Swaine's code to modify a specific node by it's name attribute, and to also modify an external config file. Hope it helps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
namespace LobbyGuard.UI.Registration
{
public class ConfigSettings
{
private static string NodePath = "//system.serviceModel//client//endpoint";
private ConfigSettings() { }
public static string GetEndpointAddress()
{
return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
}
public static void SaveEndpointAddress(string endpointAddress)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNodeList nodes = doc.SelectNodes(NodePath);
foreach (XmlNode node in nodes)
{
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
//If this isnt the node I want to change, look at the next one
//Change this string to the name attribute of the node you want to change
if (node.Attributes["name"].Value != "DataLocal_Endpoint1")
{
continue;
}
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(getConfigFilePath());
break;
}
catch (Exception e)
{
throw e;
}
}
}
public static void SaveEndpointAddress(string endpointAddress, string ConfigPath, string endpointName)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument(ConfigPath);
// retrieve appSettings node
XmlNodeList nodes = doc.SelectNodes(NodePath);
foreach (XmlNode node in nodes)
{
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
//If this isnt the node I want to change, look at the next one
if (node.Attributes["name"].Value != endpointName)
{
continue;
}
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(ConfigPath);
break;
}
catch (Exception e)
{
throw e;
}
}
}
public static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(getConfigFilePath());
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
public static XmlDocument loadConfigDocument(string Path)
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(Path);
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
}
}
MyServiceClient client = new MyServiceClient(binding, endpoint);
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost/webSrvHost/service.svc");
client.Endpoint.Binding = new NetTcpBinding()
{
Name = "yourTcpBindConfig",
ReaderQuotas = XmlDictionaryReaderQuotas.Max,
ListenBacklog = 40 }
It's very easy to modify the uri in config or binding info in config.
Is this what you want?
For what it's worth, I needed to update the port and scheme for SSL for my RESTFul service. This is what I did. Apologies that it is a bit more that the original question, but hopefully useful to someone.
// Don't forget to add references to System.ServiceModel and System.ServiceModel.Web
using System.ServiceModel;
using System.ServiceModel.Configuration;
var port = 1234;
var isSsl = true;
var scheme = isSsl ? "https" : "http";
var currAssembly = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
Configuration config = ConfigurationManager.OpenExeConfiguration(currAssembly);
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);
// Get the first endpoint in services. This is my RESTful service.
var endp = serviceModel.Services.Services[0].Endpoints[0];
// Assign new values for endpoint
UriBuilder b = new UriBuilder(endp.Address);
b.Port = port;
b.Scheme = scheme;
endp.Address = b.Uri;
// Adjust design time baseaddress endpoint
var baseAddress = serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress;
b = new UriBuilder(baseAddress);
b.Port = port;
b.Scheme = scheme;
serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress = b.Uri.ToString();
// Setup the Transport security
BindingsSection bindings = serviceModel.Bindings;
WebHttpBindingCollectionElement x =(WebHttpBindingCollectionElement)bindings["webHttpBinding"];
WebHttpBindingElement y = (WebHttpBindingElement)x.ConfiguredBindings[0];
var e = y.Security;
e.Mode = isSsl ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None;
e.Transport.ClientCredentialType = HttpClientCredentialType.None;
// Save changes
config.Save();
I think what you want is to swap out at runtime a version of your config file, if so create a copy of your config file (also give it the relevant extension like .Debug or .Release) that has the correct addresses (which gives you a debug version and a runtime version ) and create a postbuild step that copies the correct file depending on the build type.
Here is an example of a postbuild event that I've used in the past which overrides the output file with the correct version (debug/runtime)
copy "$(ProjectDir)ServiceReferences.ClientConfig.$(ConfigurationName)" "$(ProjectDir)ServiceReferences.ClientConfig" /Y
where :
$(ProjectDir) is the project directory where the config files are located
$(ConfigurationName) is the active configuration build type
EDIT:
Please see Marc's answer for a detailed explanation on how to do this programmatically.
You can do it like this:
Keep your settings in a separate xml file and read through it when you create a proxy for your service.
For example , i want to modify my service endpoint address at runtime so i have the following ServiceEndpoint.xml file.
<?xml version="1.0" encoding="utf-8" ?>
<Services>
<Service name="FileTransferService">
<Endpoints>
<Endpoint name="ep1" address="http://localhost:8080/FileTransferService.svc" />
</Endpoints>
</Service>
</Services>
For reading your xml :
var doc = new XmlDocument();
doc.Load(FileTransferConstants.Constants.SERVICE_ENDPOINTS_XMLPATH);
XmlNodeList endPoints = doc.SelectNodes("/Services/Service/Endpoints");
foreach (XmlNode endPoint in endPoints)
{
foreach (XmlNode child in endPoint)
{
if (child.Attributes["name"].Value.Equals("ep1"))
{
var adressAttribute = child.Attributes["address"];
if (!ReferenceEquals(null, adressAttribute))
{
address = adressAttribute.Value;
}
}
}
}
Then get your web.config file of your client at runtime and assign the service endpoint address as:
Configuration wConfig = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = #"C:\FileTransferWebsite\web.config" }, ConfigurationUserLevel.None);
ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);
ClientSection wClientSection = wServiceSection.Client;
wClientSection.Endpoints[0].Address = new Uri(address);
wConfig.Save();
see if you are placing the client section in the correct web.config file. SharePoint has around 6 to 7 config files.
http://msdn.microsoft.com/en-us/library/office/ms460914(v=office.14).aspx (http://msdn.microsoft.com/en-us/library/office/ms460914%28v=office.14%29.aspx)
Post this you can simply try
ServiceClient client = new ServiceClient("ServiceSOAP");

How do I dynamically set up endpoint and bindings with HTTPS [duplicate]

I'd like to programmatically modify my app.config file to set which service file endpoint should be used. What is the best way to do this at runtime? For reference:
<endpoint address="http://mydomain/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
contract="ASRService.IASRService" name="WSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
Is this on the client side of things??
If so, you need to create an instance of WsHttpBinding, and an EndpointAddress, and then pass those two to the proxy client constructor that takes these two as parameters.
// using System.ServiceModel;
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("http://localhost:9000/MyService"));
MyServiceClient client = new MyServiceClient(binding, endpoint);
If it's on the server side of things, you'll need to programmatically create your own instance of ServiceHost, and add the appropriate service endpoints to it.
ServiceHost svcHost = new ServiceHost(typeof(MyService), null);
svcHost.AddServiceEndpoint(typeof(IMyService),
new WSHttpBinding(),
"http://localhost:9000/MyService");
Of course you can have multiple of those service endpoints added to your service host. Once you're done, you need to open the service host by calling the .Open() method.
If you want to be able to dynamically - at runtime - pick which configuration to use, you could define multiple configurations, each with a unique name, and then call the appropriate constructor (for your service host, or your proxy client) with the configuration name you wish to use.
E.g. you could easily have:
<endpoint address="http://mydomain/MyService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IASRService"
contract="ASRService.IASRService"
name="WSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="https://mydomain/MyService2.svc"
binding="wsHttpBinding" bindingConfiguration="SecureHttpBinding_IASRService"
contract="ASRService.IASRService"
name="SecureWSHttpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://mydomain/MyService3.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IASRService"
contract="ASRService.IASRService"
name="NetTcpBinding_IASRService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
(three different names, different parameters by specifying different bindingConfigurations) and then just pick the right one to instantiate your server (or client proxy).
But in both cases - server and client - you have to pick before actually creating the service host or the proxy client. Once created, these are immutable - you cannot tweak them once they're up and running.
Marc
I use the following code to change the endpoint address in the App.Config file. You may want to modify or remove the namespace before usage.
using System;
using System.Xml;
using System.Configuration;
using System.Reflection;
//...
namespace Glenlough.Generations.SupervisorII
{
public class ConfigSettings
{
private static string NodePath = "//system.serviceModel//client//endpoint";
private ConfigSettings() { }
public static string GetEndpointAddress()
{
return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
}
public static void SaveEndpointAddress(string endpointAddress)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNode node = doc.SelectSingleNode(NodePath);
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(getConfigFilePath());
}
catch( Exception e )
{
throw e;
}
}
public static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(getConfigFilePath());
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
}
}
SomeServiceClient client = new SomeServiceClient();
var endpointAddress = client.Endpoint.Address; //gets the default endpoint address
EndpointAddressBuilder newEndpointAddress = new EndpointAddressBuilder(endpointAddress);
newEndpointAddress.Uri = new Uri("net.tcp://serverName:8000/SomeServiceName/");
client = new SomeServiceClient("EndpointConfigurationName", newEndpointAddress.ToEndpointAddress());
I did it like this. The good thing is it still picks up the rest of your endpoint binding settings from the config and just replaces the URI.
this short code worked for me:
Configuration wConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);
ClientSection wClientSection = wServiceSection.Client;
wClientSection.Endpoints[0].Address = <your address>;
wConfig.Save();
Of course you have to create the ServiceClient proxy AFTER the config has changed.
You also need to reference the System.Configuration and System.ServiceModel assemblies to make this work.
Cheers
This is the shortest code that you can use to update the app config file even if don't have a config section defined:
void UpdateAppConfig(string param)
{
var doc = new XmlDocument();
doc.Load("YourExeName.exe.config");
XmlNodeList endpoints = doc.GetElementsByTagName("endpoint");
foreach (XmlNode item in endpoints)
{
var adressAttribute = item.Attributes["address"];
if (!ReferenceEquals(null, adressAttribute))
{
adressAttribute.Value = string.Format("http://mydomain/{0}", param);
}
}
doc.Save("YourExeName.exe.config");
}
I have modified and extended Malcolm Swaine's code to modify a specific node by it's name attribute, and to also modify an external config file. Hope it helps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;
namespace LobbyGuard.UI.Registration
{
public class ConfigSettings
{
private static string NodePath = "//system.serviceModel//client//endpoint";
private ConfigSettings() { }
public static string GetEndpointAddress()
{
return ConfigSettings.loadConfigDocument().SelectSingleNode(NodePath).Attributes["address"].Value;
}
public static void SaveEndpointAddress(string endpointAddress)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNodeList nodes = doc.SelectNodes(NodePath);
foreach (XmlNode node in nodes)
{
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
//If this isnt the node I want to change, look at the next one
//Change this string to the name attribute of the node you want to change
if (node.Attributes["name"].Value != "DataLocal_Endpoint1")
{
continue;
}
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(getConfigFilePath());
break;
}
catch (Exception e)
{
throw e;
}
}
}
public static void SaveEndpointAddress(string endpointAddress, string ConfigPath, string endpointName)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument(ConfigPath);
// retrieve appSettings node
XmlNodeList nodes = doc.SelectNodes(NodePath);
foreach (XmlNode node in nodes)
{
if (node == null)
throw new InvalidOperationException("Error. Could not find endpoint node in config file.");
//If this isnt the node I want to change, look at the next one
if (node.Attributes["name"].Value != endpointName)
{
continue;
}
try
{
// select the 'add' element that contains the key
//XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
node.Attributes["address"].Value = endpointAddress;
doc.Save(ConfigPath);
break;
}
catch (Exception e)
{
throw e;
}
}
}
public static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(getConfigFilePath());
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
public static XmlDocument loadConfigDocument(string Path)
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(Path);
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
}
}
MyServiceClient client = new MyServiceClient(binding, endpoint);
client.Endpoint.Address = new EndpointAddress("net.tcp://localhost/webSrvHost/service.svc");
client.Endpoint.Binding = new NetTcpBinding()
{
Name = "yourTcpBindConfig",
ReaderQuotas = XmlDictionaryReaderQuotas.Max,
ListenBacklog = 40 }
It's very easy to modify the uri in config or binding info in config.
Is this what you want?
For what it's worth, I needed to update the port and scheme for SSL for my RESTFul service. This is what I did. Apologies that it is a bit more that the original question, but hopefully useful to someone.
// Don't forget to add references to System.ServiceModel and System.ServiceModel.Web
using System.ServiceModel;
using System.ServiceModel.Configuration;
var port = 1234;
var isSsl = true;
var scheme = isSsl ? "https" : "http";
var currAssembly = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
Configuration config = ConfigurationManager.OpenExeConfiguration(currAssembly);
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);
// Get the first endpoint in services. This is my RESTful service.
var endp = serviceModel.Services.Services[0].Endpoints[0];
// Assign new values for endpoint
UriBuilder b = new UriBuilder(endp.Address);
b.Port = port;
b.Scheme = scheme;
endp.Address = b.Uri;
// Adjust design time baseaddress endpoint
var baseAddress = serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress;
b = new UriBuilder(baseAddress);
b.Port = port;
b.Scheme = scheme;
serviceModel.Services.Services[0].Host.BaseAddresses[0].BaseAddress = b.Uri.ToString();
// Setup the Transport security
BindingsSection bindings = serviceModel.Bindings;
WebHttpBindingCollectionElement x =(WebHttpBindingCollectionElement)bindings["webHttpBinding"];
WebHttpBindingElement y = (WebHttpBindingElement)x.ConfiguredBindings[0];
var e = y.Security;
e.Mode = isSsl ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None;
e.Transport.ClientCredentialType = HttpClientCredentialType.None;
// Save changes
config.Save();
I think what you want is to swap out at runtime a version of your config file, if so create a copy of your config file (also give it the relevant extension like .Debug or .Release) that has the correct addresses (which gives you a debug version and a runtime version ) and create a postbuild step that copies the correct file depending on the build type.
Here is an example of a postbuild event that I've used in the past which overrides the output file with the correct version (debug/runtime)
copy "$(ProjectDir)ServiceReferences.ClientConfig.$(ConfigurationName)" "$(ProjectDir)ServiceReferences.ClientConfig" /Y
where :
$(ProjectDir) is the project directory where the config files are located
$(ConfigurationName) is the active configuration build type
EDIT:
Please see Marc's answer for a detailed explanation on how to do this programmatically.
You can do it like this:
Keep your settings in a separate xml file and read through it when you create a proxy for your service.
For example , i want to modify my service endpoint address at runtime so i have the following ServiceEndpoint.xml file.
<?xml version="1.0" encoding="utf-8" ?>
<Services>
<Service name="FileTransferService">
<Endpoints>
<Endpoint name="ep1" address="http://localhost:8080/FileTransferService.svc" />
</Endpoints>
</Service>
</Services>
For reading your xml :
var doc = new XmlDocument();
doc.Load(FileTransferConstants.Constants.SERVICE_ENDPOINTS_XMLPATH);
XmlNodeList endPoints = doc.SelectNodes("/Services/Service/Endpoints");
foreach (XmlNode endPoint in endPoints)
{
foreach (XmlNode child in endPoint)
{
if (child.Attributes["name"].Value.Equals("ep1"))
{
var adressAttribute = child.Attributes["address"];
if (!ReferenceEquals(null, adressAttribute))
{
address = adressAttribute.Value;
}
}
}
}
Then get your web.config file of your client at runtime and assign the service endpoint address as:
Configuration wConfig = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = #"C:\FileTransferWebsite\web.config" }, ConfigurationUserLevel.None);
ServiceModelSectionGroup wServiceSection = ServiceModelSectionGroup.GetSectionGroup(wConfig);
ClientSection wClientSection = wServiceSection.Client;
wClientSection.Endpoints[0].Address = new Uri(address);
wConfig.Save();
see if you are placing the client section in the correct web.config file. SharePoint has around 6 to 7 config files.
http://msdn.microsoft.com/en-us/library/office/ms460914(v=office.14).aspx (http://msdn.microsoft.com/en-us/library/office/ms460914%28v=office.14%29.aspx)
Post this you can simply try
ServiceClient client = new ServiceClient("ServiceSOAP");

SolrNet: SolrConnectionException (400) bad request when attempting to Add and Commit

I have gotten to the point where SolrNet executes the "Add" method but when I try to "Commit" is when I receive the error. The following is my schema.xml, model, code calling it, and the error I get. Even stranger is that despite the error, the model is added to my Solr index AFTER I restart Tomcat (so it still adds my model despite the error but not immediately):
schema.xml (fields and fieldtypes):
<!-- Fields -->
<field name="part_numbers" type="my_string_exact" indexed="true" stored="true" multiValued="true" />
<field name="page_url" type="my_string_exact" indexed="true" stored="true" />
<field name="product_name" type="my_string" indexed="true" stored="true" />
<!-- FieldTypes -->
<fieldType name="my_string_exact" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="my_string" class="solr.TextField" sortMissingLast="true" omitNorms="true">
<analyzer type="index">
<tokenizer class="solr.KeywordTokenizerFactory" />
<filter class="solr.LowerCaseFilterFactory" />
</analyzer>
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory" />
<filter class="solr.LowerCaseFilterFactory" />
</analyzer>
</fieldType>
<fieldType name="my_int" class="solr.IntField" omitNorms="true" />
Model (Product.cs) *NOTE - PageId uses the Solr default "id" that is a string, unique and required:
public class Product
{
[SolrUniqueKey("id")]
public string PageId { get; set; }
[SolrField("part_numbers")]
public ICollection<string> PartNumbers { get; set; }
[SolrField("page_url")]
public string PageUrl { get; set; }
[SolrField("product_name")]
public string Name { get; set; }
}
Code initializing, calling the Add and Commit *NOTE - This is a unit test so init is only called once:
Startup.Init<Product>("http://localhost:8080/solr");
Product testProd = new Product() {
EPiPageId = "44",
Name = "TestProd3",
PageUrl = "/TestProd3",
PartNumbers = new List<string>() { "000022222", "000000333333" }
};
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Product>>();
solr.Add(testProd);
solr.Commit(); // Bad Request Error occurs here.
Error Msg:
SolrNet.Exceptions.SolrConnectionException was unhandled by user code
HResult=-2146232832
Message=The remote server returned an error: (400) Bad Request.
Source=SolrNet
StackTrace:
at SolrNet.Impl.SolrConnection.Post(String relativeUrl, String s) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrConnection.cs:line 104
at SolrNet.Commands.CommitCommand.Execute(ISolrConnection connection) in c:\prg\SolrNet\svn\SolrNet\Commands\CommitCommand.cs:line 71
at SolrNet.Impl.SolrBasicServer`1.Send(ISolrCommand cmd) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrBasicServer.cs:line 87
at SolrNet.Impl.SolrBasicServer`1.SendAndParseHeader(ISolrCommand cmd) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrBasicServer.cs:line 91
at SolrNet.Impl.SolrBasicServer`1.Commit(CommitOptions options) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrBasicServer.cs:line 54
at SolrNet.Impl.SolrServer`1.Commit() in c:\prg\SolrNet\svn\SolrNet\Impl\SolrServer.cs:line 24
InnerException: System.Net.WebException
HResult=-2146233079
Message=The remote server returned an error: (400) Bad Request.
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at HttpWebAdapters.Adapters.HttpWebRequestAdapter.GetResponse() in c:\prg\SolrNet\svn\HttpWebAdapters\Impl\HttpWebRequestAdapter.cs:line 36
at SolrNet.Impl.SolrConnection.GetResponse(IHttpWebRequest request) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrConnection.cs:line 160
at SolrNet.Impl.SolrConnection.Post(String relativeUrl, String s) in c:\prg\SolrNet\svn\SolrNet\Impl\SolrConnection.cs:line 101
InnerException:
EDIT Thanks to Paige for the answer: The issue was a "waitFlush" error that is a bug with older versions of SolrNet. The version of SolrNet that I was using was from VS NuGet that was 0.3.1 (which I assumed was their latest stable build). Their google code site does not have their most recent build but the build server (here: http://teamcity.codebetter.com/project.html?projectId=project36&guest=1 under "artifacts") did have the latest with the fix to this bug. Problem solved for me.
I am guessing that you are probably seeing a waitFlush error in your Tomcat Logs and you are using version 4.X of Solr. If that is the case, this is a known issue with Solr 4.x and older versions of SolrNet. To fix this issue, upgrade to a later release of the SolrNet library. You can download it from the Build Server. Click on Artifacts to get a link to the zip.

Modifying app.config via custom msi installer

I need to create an address string in app.config as:
<client>
<endpoint address="http://ServerName/xxx/yyy.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IClientIInfoService"
contract="DocuHealthLinkSvcRef.IClientIInfoService" name="BasicHttpBinding_IClientIInfoService" />
</client>
The ServerName need to be entered by the user during installation.
For that i have created a new UI dialog in the Installer. I have also written an Installer.cs class and overrided the install () as:
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string targetDirectory = Context.Parameters["targetdir"];
string ServerName = Context.Parameters["ServerName"];
System.Diagnostics.Debugger.Break();
string exePath = string.Format("{0}myapp.exe", targetDirectory);
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
config.AppSettings.Settings["ServerName"].Value = ServerName;
config.Save();
}
}
But how do i use this ServerName in my app.config to create the specified string.
I'm working on VS2010.
You could use WiX (Windows Installer XML toolset) to build your MSI, in which case you can use the XmlFile utility tag to update the server name:
<util:XmlFile Id="UpdateServerName" File="[INSTALLLOCATION]AppName.exe.config" Action="setValue" ElementPath="/client/endpoint" Name="address" Value="http://[SERVERNAME]/xxx/yyy.svc" />
You can capture the server name during installation using a WixUI extension form.
Advantages of WiX: WiX is msbuild compliant (unlike .vdproj files), and gives you much finer-grained control over your installer, among other things
Assuming you are using the full ServiceModel section group in the app.config
Essentially you follow these steps:
Load ServiceModel config section
Get Client Section
Get ChannelEndpoint Element
Change Address value by replacing string "ServerName" with entered value
Set Address attribute to new value
Save config
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string targetDirectory = Context.Parameters["targetdir"];
string ServerName = Context.Parameters["ServerName"];
System.Diagnostics.Debugger.Break();
string exePath = string.Format("{0}myapp.exe", targetDirectory);
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
config.AppSettings.Settings["ServerName"].Value = ServerName;
//Get ServiceModelSectionGroup from config
ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup (config);
//get the client section
ClientSection clientSection = group.Client;
//get the first endpoint
ChannelEndpointElement channelEndpointElement = clientSection.Endpoints[0];
//get the address attribute and replace servername in the string.
string address = channelEndpointElement.Address.ToString().Replace("ServerName", ServerName);
//set the Address attribute to the new value
channelEndpointElement.Address = new Uri(address);
config.Save();
}
At the end of the day, app.config is xml file. You can use Linq To XML or XPathNavigator to replace the address attribute of endpoint element.
Below code uses Linq to Xml
using System.Xml.Linq;
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
string targetDirectory = Context.Parameters["targetdir"];
string ServerName = Context.Parameters["ServerName"];
System.Diagnostics.Debugger.Break();
string configPath = string.Format("{0myapp.exe.config", targetDirectory);
XElement root = XElement.Load(configPath);
var endPointElements = root.Descendants("endpoint");
foreach(var element in endPointElements)
{
element.Attribute("address").Value = ServerName;
}
root.Save(configPath);
}
}
Since you have a windows-installer tag, I assume you either have an MSI package, or can create one...
Then:
You can create a public MSI property like ENDPOINTSERVER you require
during installation.
Add a custom action that modifies app.config to
run after "InstallFinalize" with the value of ENDPOINTSERVER
A silent installation will be possible using:
msiexec /i app.msi ENDPOINTSERVER=www.MyServer.com /qb-
try to use below two lines before saving the config file changes:
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("Section Name");
root.Save(configPath);
P.S: it doesn't update the solution item 'app.config', but the '.exe.config' one in the bin/ folder if you run it with F5.

Categories

Resources