I want to connect to a webservice url which is provided at runtime when user logs in. so i need to set Endpoint.Address in app.config at runtime.
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("host/mikev-ws");
Uri uri = new Uri(txtURL.text.trim());
var address = new EndpointAddress(uri, spn);
var client = new EchoServiceClient("WSHttpBinding_IEchoService", address);
client.Close();
I placed this code on button click ,and gets the value of uri from textbox. Code is executing correctly and then getting an error message
"Address property on channelfactory.endpoint was null"
my app.config is:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="LoginServiceSoap" />
</basicHttpBinding>
</bindings>
<client>
<!--<endpoint address="http://localhost:3073/LoginService.asmx" binding="basicHttpBinding"-->
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="LoginServiceSoap" contract="LoginService.LoginServiceSoap"
name="LoginServiceSoap" />
</client>
</system.serviceModel>
</configuration>
I've done something similar in a recent project, where I only wanted to set the endpoint and authentication programatically and not use the config file at all:
public static class ServiceClientFactory
{
public static HttpBindingBase BuildNavisionBinding(string endpointUrl)
{
//http://blog.randomdust.com/index.php/2010/10/could-not-establish-trust-relationship-for-the-ssl-tls-secure-channel/
//http://www.codeproject.com/Forums/1649/Csharp.aspx?fid=1649&df=90&mpp=25&sort=Position&select=3126652&tid=3121885
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate
{
return true;
});
if (endpointUrl.ToLower().StartsWith("https"))
{
var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.MaxReceivedMessageSize = int.MaxValue - 1;
return binding;
}
else
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.MaxReceivedMessageSize = int.MaxValue - 1;
return binding;
}
}
public static TClient CreateClient<TClient, TChannel>(string endpoint, string username, string password)
where TClient : ClientBase<TChannel>
where TChannel : class
{
var client = (TClient)
Activator.CreateInstance(
typeof (TClient),
BuildNavisionBinding(endpoint),
new EndpointAddress(endpoint));
if (null == client.ClientCredentials)
throw new Exception(
string.Format("Error initializing [{0}] client. Client Credentials object was null",
typeof(TClient).Name));
client.ClientCredentials.Windows.ClientCredential =
new NetworkCredential(
username,
password);
client.ClientCredentials.Windows.AllowedImpersonationLevel =
TokenImpersonationLevel.Delegation;
client.Endpoint.Binding.SendTimeout = new TimeSpan(0, 0, 4, 0);
client.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 4, 0);
client.Endpoint.Binding.OpenTimeout = new TimeSpan(0, 0, 4, 0);
return client;
}
So from your example:
var client = ServiceClientFactory.CreateClient<EchoServiceClient, IEchoServicePort(txtUrl.text.trim(), /* authentication */);
Related
I'm developing android app on Xamarin Android in c#.
Is there any way to change dynamically URL of SOAP web service? I want to store url in some kind of config file but I have no idea how do it.
correct me, if i'm wrong
but the second constructor of an xamarin - soap webservice class has a property for URL.
Here's an example of my webservice:
public partial class Service : System.Web.Services.Protocols.SoapHttpClientProtocol
{
public Service()
{
this.Url = "http://xxx/service.asmx";
}
public Service(string url)
{
this.Url = url;
}
}
you've added the webreference in xamarin and then use your webservice - instance.
Just call the second constructor and give them an other url as source.
You could manually create your required connection using Channelfactory that changes as it needs to. You'll need the proper connections in the web.config file.
Here's a way you could set it up.
In your web.config.
<appSettings>
<add key="Identity" value="machineidentity" />
<add key="Binding" value="WSHttpBinding_IService" />
<add key="Endpoint" value="http://Devservice/Service.svc" />
<add key="Identity2" value="localmachine" />
<add key="Binding2" value="WSHttpBinding_IService" />
<add key="Endpoint2" value="http://Devservice/Service.svc" />
<add key="devIdentity" value="localmachine" />
<add key="devBinding" value="WSHttpBinding_IService" />
<add key="devEndpoint" value="http://Devservice/Service.svc" />
</appSettings>
C# code
a configuration class to hold values from the web.config
public static Dictionary<int, Connections> EndpointConnections = new Dictionary<int, Connections>
{
{1, new Connections(){Identity = ConfigurationManager.AppSettings["Identity"],Binding = ConfigurationManager.AppSettings["Binding"], Endpoint = ConfigurationManager.AppSettings["Endpoint"]}},
{2, new Connections(){Identity = ConfigurationManager.AppSettings["Identity2"],Binding = ConfigurationManager.AppSettings["Binding2"], Endpoint = ConfigurationManager.AppSettings["Endpoint2"]}},
{3, new Connections(){Identity = ConfigurationManager.AppSettings["devIdentity"],Binding = ConfigurationManager.AppSettings["devBinding"], Endpoint = ConfigurationManager.AppSettings["devEndpoint"]}},
};
Now a static class for creating the endpoint
private ChannelFactory<IService> SetChannelFactory(int configInput)
{
var identity = EndpointIdentity.CreateDnsIdentity(Configuration.EndpointConnections[configInput].Identity);
var myBinding = new WSHttpBinding(Configuration.EndpointConnections[configInput].Binding);
var myuri = new Uri(Configuration.EndpointConnections[configInput].Endpoint);
var myEndpoint = new EndpointAddress(myuri, identity);
return new ChannelFactory<IService>(myBinding, myEndpoint);
}
Now calling and using the endpoint
public async Task<Result> SomeAction(int selection)
{
IService client = null;
Result result = null;
Response response = null;
using (var myChannelFactory = SetChannelFactory(selection))
{
try
{
client = myChannelFactory.CreateChannel();
response = await client.TheServiceFunction().ConfigureAwait(false);
((ICommunicationObject)client).Close();
}
catch
{
if (client != null)
{
((ICommunicationObject)client).Abort();
return new result ( failure = true);
}
}
}
if (response != null)
{
//Whatever you want to do with the response here
return new result ( failure = false);
}
}
I have a client for SOAP service in a console application, I need to move the service client to sharepoint 2010. I do not want to do config files deployment and other sharepoint-related stuff, so I decided to hardcode binding information, the only configurable option is URL. But I encountred some troubles doing this. I have a config:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="SI_PMProjectMaintain_SOUTBinding">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap11" writeEncoding="utf-8">
<readerQuotas maxDepth="10000000" maxStringContentLength="10000000"
maxArrayLength="67108864" maxBytesPerRead="65536" maxNameTableCharCount="100000" />
</textMessageEncoding>
<httpTransport authenticationScheme="Basic" bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard" keepAliveEnabled="false"
proxyAuthenticationScheme="Basic" realm="XISOAPApps" useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://url/XISOAPAdapter/MessageServlet?senderParty=&senderService=Param1&receiverParty=&receiverService=&interface=interface&interfaceNamespace=url"
binding="customBinding" bindingConfiguration="SI_PMProjectMaintain_SOUTBinding"
contract="PmProjectMaintain.SI_PMProjectMaintain_SOUT" name="HTTP_Port" />
</client>
Also, I have a code:
var service = new ServiceClient();
service.ClientCredentials.Windows.ClientCredential = new NetworkCredential("user", "password");
service.ClientCredentials.UserName.UserName = "user";
service.ClientCredentials.UserName.Password = "password";
var resp = service.Operation();
Console.WriteLine(resp.Response);
It works as expected. Now I want to get rid of xml config and completly move it to code:
public class CustomHttpTransportBinding : CustomBinding
{
public CustomHttpTransportBinding()
{
}
public override BindingElementCollection CreateBindingElements()
{
var result = new BindingElementCollection();
result.Add(new TextMessageEncodingBindingElement
{
MaxReadPoolSize = 64,
MaxWritePoolSize = 16,
MessageVersion = MessageVersion.Soap11,
WriteEncoding = Encoding.UTF8,
//ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas
//{
// MaxDepth = 10000000,
// MaxStringContentLength = 10000000,
// MaxArrayLength = 67108864,
// MaxBytesPerRead = 65536,
// MaxNameTableCharCount = 100000
//}
});
result.Add(new HttpTransportBindingElement
{
AuthenticationScheme = AuthenticationSchemes.Basic,
BypassProxyOnLocal = false,
HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard,
KeepAliveEnabled = false,
ProxyAuthenticationScheme = AuthenticationSchemes.Basic,
Realm = "XISOAPApps",
UseDefaultWebProxy = true
});
return result;
}
}
And I use it like this:
var service = new ServiceClient(new CustomHttpTransportBinding(), new EndpointAddress(url));
service.ClientCredentials.Windows.ClientCredential = new NetworkCredential("user", "password");
service.ClientCredentials.UserName.UserName = "user";
service.ClientCredentials.UserName.Password = "password";
var resp = service.Operation();
Console.WriteLine(resp.Response);
It reaches the server, but throws exception ("Server Error"), so I belive something wrong with my configuration. I can not specify the reader quotas also. I've tried loading configuration from string, but it is not worked for me, same error.
Confi
It seems that I can not convert custom bindings from XML to code in .net 3.5. Can somebody take a look on my code and confirm? Are there other ways to have a service client with custom binding in code?
I have not found a way to move configuration from app.config to code for a custom binding, it works greate for basicHttpBinding, but does not work for customBinding.
I've ended up with loading the configuration dynamicaly from file using custom chanell factory.
public class CustomChannelFactory<T> : ChannelFactory<T>
{
private readonly string _configurationPath;
public CustomChannelFactory(string configurationPath) : base(typeof(T))
{
_configurationPath = configurationPath;
base.InitializeEndpoint((string)null, null);
}
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint serviceEndpoint = base.CreateDescription();
ExeConfigurationFileMap executionFileMap = new ExeConfigurationFileMap();
executionFileMap.ExeConfigFilename = _configurationPath;
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(executionFileMap, ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModeGroup = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
foreach (ChannelEndpointElement endpoint in serviceModeGroup.Client.Endpoints)
{
if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)
{
selectedEndpoint = endpoint;
break;
}
}
if (selectedEndpoint != null)
{
if (serviceEndpoint.Binding == null)
{
serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, serviceModeGroup);
}
if (serviceEndpoint.Address == null)
{
serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
}
if (serviceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))
{
AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, serviceModeGroup);
}
serviceEndpoint.Name = selectedEndpoint.Contract;
}
return serviceEndpoint;
}
private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group)
{
BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];
if (bindingElementCollection.ConfiguredBindings.Count > 0)
{
IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
Binding binding = GetBinding(be);
if (be != null)
{
be.ApplyConfiguration(binding);
}
return binding;
}
return null;
}
private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint, ServiceModelSectionGroup group)
{
EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors[behaviorConfiguration];
for (int i = 0; i < behaviorElement.Count; i++)
{
BehaviorExtensionElement behaviorExtension = behaviorElement[i];
object extension = behaviorExtension.GetType().InvokeMember("CreateBehavior",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, behaviorExtension, null);
if (extension != null)
{
serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension);
}
}
}
private EndpointIdentity GetIdentity(IdentityElement element)
{
EndpointIdentity identity = null;
PropertyInformationCollection properties = element.ElementInformation.Properties;
if (properties["userPrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value);
}
if (properties["servicePrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value);
}
if (properties["dns"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateDnsIdentity(element.Dns.Value);
}
if (properties["rsa"].ValueOrigin != PropertyValueOrigin.Default)
{
return EndpointIdentity.CreateRsaIdentity(element.Rsa.Value);
}
if (properties["certificate"].ValueOrigin != PropertyValueOrigin.Default)
{
X509Certificate2Collection supportingCertificates = new X509Certificate2Collection();
supportingCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue));
if (supportingCertificates.Count == 0)
{
throw new InvalidOperationException("UnableToLoadCertificateIdentity");
}
X509Certificate2 primaryCertificate = supportingCertificates[0];
supportingCertificates.RemoveAt(0);
return EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate, supportingCertificates);
}
return identity;
}
private Binding GetBinding(IBindingConfigurationElement configurationElement)
{
if (configurationElement is CustomBindingElement)
return new CustomBinding();
else if (configurationElement is BasicHttpBindingElement)
return new BasicHttpBinding();
else if (configurationElement is NetMsmqBindingElement)
return new NetMsmqBinding();
else if (configurationElement is NetNamedPipeBindingElement)
return new NetNamedPipeBinding();
else if (configurationElement is NetPeerTcpBindingElement)
return new NetPeerTcpBinding();
else if (configurationElement is NetTcpBindingElement)
return new NetTcpBinding();
else if (configurationElement is WSDualHttpBindingElement)
return new WSDualHttpBinding();
else if (configurationElement is WSHttpBindingElement)
return new WSHttpBinding();
else if (configurationElement is WSFederationHttpBindingElement)
return new WSFederationHttpBinding();
return null;
}
}
Usefull links:
Loading WCF configuration from different files (source code is not availiable)
Thread with source code of CustomChannelFactory
.NET 4.0 ChanellFactory (wish it was in .net 3.5)
Found an issue with the code referenced in boades reply, in that if you have mixed transport bindings (https/http) under basicHttpbinding you are likely to get an exception similar/reverse of this:
The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via
I'd also expect you will also have unexpected authorization occurring, again as the code will use the first bindingConfiguration listed in the web.config rather than by name.
The offending line which doesn't take the binding by name, but rather just takes the 1st one(!)
IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
This could be corrected by updating CreateBinding method and the call in CreateDescription like so:
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint description = base.CreateDescription();
if (CustomisedChannelFactory<TChannel>.ConfigurationPath == null || !System.IO.File.Exists(CustomisedChannelFactory<TChannel>.ConfigurationPath))
return base.CreateDescription();
ServiceModelSectionGroup sectionGroup = ServiceModelSectionGroup.GetSectionGroup(ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
{
ExeConfigFilename = CustomisedChannelFactory<TChannel>.ConfigurationPath
}, ConfigurationUserLevel.None));
ChannelEndpointElement channelEndpointElement1 = (ChannelEndpointElement)null;
foreach (ChannelEndpointElement channelEndpointElement2 in (ConfigurationElementCollection)sectionGroup.Client.Endpoints)
{
if (channelEndpointElement2.Contract == description.Contract.ConfigurationName)
{
channelEndpointElement1 = channelEndpointElement2;
break;
}
}
if (channelEndpointElement1 != null)
{
if (description.Binding == null)
description.Binding = this.CreateBinding(channelEndpointElement1.Binding, channelEndpointElement1.BindingConfiguration, sectionGroup);
if (description.Address == (EndpointAddress)null)
description.Address = new EndpointAddress(channelEndpointElement1.Address, this.GetIdentity(channelEndpointElement1.Identity), channelEndpointElement1.Headers.Headers);
if (description.Behaviors.Count == 0 && !string.IsNullOrEmpty(channelEndpointElement1.BehaviorConfiguration))
this.AddBehaviors(channelEndpointElement1.BehaviorConfiguration, description, sectionGroup);
description.Name = channelEndpointElement1.Contract;
}
return description;
}
private Binding CreateBinding(string bindingName, string bindingConfigurationName, ServiceModelSectionGroup group)
{
BindingCollectionElement collectionElement = group.Bindings[bindingName];
if (collectionElement.ConfiguredBindings.Count <= 0)
return (Binding)null;
IBindingConfigurationElement configurationElement = null;
foreach (IBindingConfigurationElement bce in collectionElement.ConfiguredBindings)
{
if (bce.Name.Equals(bindingConfigurationName))
{
configurationElement = bce;
break;
}
}
if (configurationElement == null) throw new Exception("BindingConfiguration " + bindingConfigurationName + " not found under binding " + bindingName);
Binding binding = this.GetBinding(configurationElement);
if (configurationElement != null)
configurationElement.ApplyConfiguration(binding);
return binding;
}
I am implementing an ipCamera/encoder management system in C#. The system will manage multiple ipCameras and/or encoders from a multiple vendors. Using Onvif instead off each ipcamera or encoders sdk will be a benefit.
One of the key concepts of the management system is to listen on events, such as motion detection events, from the cameras. Onvif supports this by use of the ws-basenotification or a pull type support. I don’t like pull, so I will use ws-basenotification support in Onvif (Onvif spec 9.1).
I have successfully added subscription to a Sony SNC-RH164, Bosh VIP X1 XF IVA and Acti TCD2100.
My problem is: I don’t get any notifications from any of the devices. Can anyone see what I'm doing wrong or give my som pointers on how to get notifications from devices.
My pc is on the same subnet as the devices. And my firewall is turned off for the test.
My test console app initiating the OnvifManager class.
using (var manager = new OnvifManager())
{
//manager.ScanForDevices();
var sonyDevice = new OnvifClassLib.OnvifDevice
{
OnvifDeviceServiceUri = new Uri(#"http://192.168.0.101/onvif/device_service"),
};
manager.AddDevice(sonyDevice);
manager.AddEventSubscription(sonyDevice, "PT1H");
var boshDevice = new OnvifClassLib.OnvifDevice
{
OnvifDeviceServiceUri = new Uri(#"http://192.168.0.102/onvif/device_service"),
};
manager.AddDevice(boshDevice);
manager.AddEventSubscription(boshDevice, string.Empty);
var actiDevice = new OnvifClassLib.OnvifDevice
{
OnvifDeviceServiceUri = new Uri(#"http://192.168.0.103/onvif/device_service"),
UserName = "uid",
Password = "pwd"
};
manager.AddDevice(actiDevice);
manager.AddEventSubscription(actiDevice);
Console.WriteLine("Waiting...");
Console.Read();
}
My managerClass will in the Constructor initialize my NotificationConsumer interface.
private void InitializeNotificationConsumerService()
{
_notificationConsumerService = new NotificationConsumerService();
_notificationConsumerService.NewNotification += NotificationConsumerService_OnNewNotification;
_notificationConsumerServiceHost = new ServiceHost(_notificationConsumerService);
_notificationConsumerServiceHost.Open();
}
My NotificationConsumer interface implementation.
/// <summary>
/// The client reciever service for WS-BaseNotification
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class NotificationConsumerService : NotificationConsumer
{
public event EventHandler<EventArgs<Notify1>> NewNotification;
/// <summary>
/// Notifies the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <remarks>A </remarks>
public void Notify(Notify1 request)
{
var threadSafeEventHandler = NewNotification;
if (threadSafeEventHandler != null)
threadSafeEventHandler.Invoke(this, new EventArgs<Notify1>(request));
}
}
public class EventArgs<T> : EventArgs
{
public EventArgs(T data)
{
Data = data;
}
public T Data { get; set; }
}
The config for NotificationConsumerService
<services>
<service name="OnvifClassLib.NotificationConsumerService">
<endpoint address="" binding="customBinding" bindingConfiguration="CustomBasicHttpBinding"
name="CustomHttpBinding" contract="EventService.NotificationConsumer" />
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.10:8080/NotificationConsumerService" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<customBinding>
<binding name="CustomBasicHttpBinding">
<textMessageEncoding messageVersion="Soap12">
<readerQuotas maxStringContentLength="80000" />
</textMessageEncoding>
<httpTransport maxReceivedMessageSize="800000" maxBufferSize="800000" />
</binding>
</customBinding>
</bindings>
The AddDevice method
public void AddDevice(OnvifDevice device)
{
LoadCapabilities(device);
OnvifDevices.Add(device);
}
internal void LoadCapabilities(OnvifDevice onvifDevice)
{
if (onvifDevice.OnvifDeviceServiceUri == null)
return;
if (onvifDevice.DeviceClient == null)
LoadDeviceClient(onvifDevice);
try
{
onvifDevice.Capabilities = onvifDevice.DeviceClient.GetCapabilities(new[] { OnvifClassLib.DeviceManagement.CapabilityCategory.All });
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
}
private void LoadDeviceClient(OnvifDevice onvifDevice)
{
if (onvifDevice.OnvifDeviceServiceUri == null)
return;
var serviceAddress = new EndpointAddress(onvifDevice.OnvifDeviceServiceUri.ToString());
var binding = GetBindingFactory(onvifDevice);
onvifDevice.DeviceClient = new OnvifClassLib.DeviceManagement.DeviceClient(binding, serviceAddress);
if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
{
onvifDevice.DeviceClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
onvifDevice.DeviceClient.ClientCredentials.UserName.Password = onvifDevice.Password;
}
}
The AddEventSubscription method
public void AddEventSubscription(OnvifDevice onvifDevice, string initialTerminationTime = "PT2H")
{
if (onvifDevice.Capabilities.Events == null)
throw new ApplicationException("The streamer info does not support event");
try
{
if (onvifDevice.NotificationProducerClient == null)
LoadNotificationProducerClient(onvifDevice);
XmlElement[] filterXml = null;
var subScribe = new Subscribe()
{
ConsumerReference = new EndpointReferenceType
{
Address = new AttributedURIType { Value = _notificationConsumerServiceHost.BaseAddresses.First().ToString() },
}
};
if (!string.IsNullOrWhiteSpace(initialTerminationTime))
subScribe.InitialTerminationTime = initialTerminationTime;
onvifDevice.SubscribeResponse = onvifDevice.NotificationProducerClient.Subscribe(subScribe);
Console.WriteLine("Listening on event from {0}", onvifDevice.NotificationProducerClient.Endpoint.Address.Uri.ToString());
}
catch (FaultException ex)
{
Console.Write(ex.ToString());
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
}
private void LoadNotificationProducerClient(OnvifDevice onvifDevice)
{
var serviceAddress = new EndpointAddress(onvifDevice.Capabilities.Events.XAddr.ToString());
var binding = GetBindingFactory(onvifDevice);
onvifDevice.NotificationProducerClient = new OnvifClassLib.EventService.NotificationProducerClient(binding, serviceAddress);
if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
{
onvifDevice.NotificationProducerClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
onvifDevice.NotificationProducerClient.ClientCredentials.UserName.Password = onvifDevice.Password;
}
}
Bindings for Soap12
private Binding GetBindingFactory(OnvifDevice onvifDevice)
{
return GetCustomBinding(onvifDevice);
}
private Binding GetCustomBinding(OnvifDevice onvifDevice)
{
HttpTransportBindingElement transportElement = new HttpTransportBindingElement();
if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
transportElement.AuthenticationScheme = AuthenticationSchemes.Basic;
var messegeElement = new TextMessageEncodingBindingElement();
messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);
var binding = new CustomBinding(messegeElement, transportElement);
binding.SendTimeout = new TimeSpan(0, 10, 0);
return binding;
}
I had this problem with a GrandStream camera. I had to add one or more detection zones to it using the camera web UI to get it to detect motion.
I think the problem is, that your notification consumer uses AddressingVersion.None, while the notifications from the ONVIF device are formatted according to WS-Addressing 1.0. Try to change the following line of your GetCustomBinding method:
messegeElement.MessageVersion = MessageVersion.CreateVersion(
EnvelopeVersion.Soap12, AddressingVersion.None);
to
messegeElement.MessageVersion = MessageVersion.CreateVersion(
EnvelopeVersion.Soap12, AddressingVersion.WSAddressing10);
I have create a EndpointAddress like that
EndpointAddress address = new EndpointAddress("http://example.com/services/OrderService.svc");
But I could not add the Behavior to this Endpoint programmatically.
The behavior is given below.:
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior">
<dataContractSerializer maxItemsInObjectGraph="6553600" />
</behavior>
</endpointBehaviors>
</behaviors>
On the server you have to add it in the ServiceBehavior Attribute:
[ServiceBehavior(MaxItemsInObjectGraph = int.MaxValue)]
On the client you have to apply it to the endpoint. In this example you can see how to add it to all the endpoints in your ChannelFactory:
var factory = new ChannelFactory<IInterface>(...);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
var dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = int.MaxValue;
}
}
On Server Side, you can also:
ServiceHost host = new ServiceHost();
ServiceBehaviorAttribute sba = host .Description.Behaviors.Find<ServiceBehaviorAttribute>();
if (sba == null)
{
sba = new ServiceBehaviorAttribute();
sba.MaxItemsInObjectGraph = int.MaxValue;
host.Description.Behaviors.Add(sba);
}
Alternative: ((ServiceBehaviorAttribute) host.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).MaxItemsInObjectGraph = int.MaxValue;
I have a app.config file that in the form of :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://something.com"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFileTransfer"
contract="ABC" name="XXX" />
<endpoint address="http://something2.com"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFileTransfer"
contract="ABC2" name="YYY" />
</client>
</system.serviceModel>
</configuration>
I want to read the value at attribute "address" of node endpoint which has the name="XXX". Please show me how to do it!
(Continue belowing disscussing with marc_s. Sorry to put the text here since comment do not allow to format codes )
#marc_s: I use the below codes to read the above file but it shows that the clientSection.Endpoints has 0 members (Count=0). Please help!
public MainWindow()
{
var exeFile = Environment.GetCommandLineArgs()[0];
var configFile = String.Format("{0}.config", exeFile);
var config = ConfigurationManager.OpenExeConfiguration(configFile);
var wcfSection = ServiceModelSectionGroup.GetSectionGroup(config);
var clientSection = wcfSection.Client;
foreach (ChannelEndpointElement endpointElement in clientSection.Endpoints)
{
if (endpointElement.Name == "XXX")
{
var addr = endpointElement.Address.ToString();
}
}
}
You really don't need to - the WCF runtime will do all of that for you.
If you really must - for whatever reason - you can do this:
using System.Configuration;
using System.ServiceModel.Configuration;
ClientSection clientSettings = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
string address = null;
foreach(ChannelEndpointElement endpoint in clientSettings.Endpoints)
{
if(endpoint.Name == "XXX")
{
address = endpoint.Address.ToString();
break;
}
}
You can use the ServiceModelSectionGroup (System.ServiceModel.Configuration) to access the configuration:
var config = ConfigurationManager.GetSection("system.serviceModel") as ServiceModelSectionGroup;
foreach (ChannelEndpointElement endpoint in config.Client.Endpoints)
{
Uri address = endpoint.Address;
// Do something here
}
Hope that helps.
var config = ConfigurationManager.OpenExeConfiguration("MyApp.exe.config");
var wcfSection = ServiceModelSectionGroup.GetSectionGroup(config);
var clientSection = wcfSection.Client;
foreach(ChannelEndpointElement endpointElement in clientSection.Endpoints) {
if(endpointElement.Name == "XXX") {
return endpointElement.Address;
}
}