ONVIF PullPointSubscriptionClient.PullMessages - c#

I'm trying to get event messages from some ONVIF devices. My code is in C#.
On a (Axis camera) device on EventPortTypeClient.CreatePullPointSubscription returns:
Address.Value: http : / /192.168.8.48/onvif/services
ReferenceParameters.Any.First().OuterXml: <dom0:SubscriptionId xmlns:dom0="http : / /www.axis.com/2009/event">38</dom0:SubscriptionId>
So I add the "To" and "SubscriptionId" soap headers and can get event messages with PullPointSubscriptionClient.PullMessages("PT5M", 99, Any, out CurrentTime, out NotificationMessages)
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest</a:Action>
<a:MessageID>urn:uuid:f243dbe4-b082-4a6c-aa65-8145468fcf3e</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0zfnhoyh15KqPZwP/IS9H0AAAAAdCoo8EjbCUScx/bG/DGcdXp8kY6WrAJDp0TTtNAtj0EACQAA</VsDebuggerCausalityData>
<Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-GWt5XP2ogUljZ/fzEJvnX0WhGpx3FV4i/dRnE539OFU=">
<wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">root</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">pjwOOO0hOXtUZyJb6B6Lb0ctRIU=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">DEE/P1c/P1E/eG9XTT87Pz8/</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2015-03-02T19:06:54.269Z</wsu:Created>
</wsse:UsernameToken>
</Security>
<a:To s:mustUnderstand="1">http://192.168.8.48/onvif/services</a:To>
<SubscriptionId s:mustUnderstand="1" xmlns="http://www.axis.com/2009/event">38</SubscriptionId>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PullMessages xmlns="http://www.onvif.org/ver10/events/wsdl">
<Timeout>PT5M</Timeout>
<MessageLimit>99</MessageLimit>
</PullMessages>
</s:Body>
</s:Envelope>
But with devices that only return Address.Value's like:
(DAHUA) Address.Value:
http : / /192.168.8.243/onvif/Subscription?Idx=57
(Siqura) Address.Value:
http : / /192.168.8.14/onvif/events_service/SubscriptionManager/15000
I add only the "To" soap header, but the PullPointSubscriptionClient.PullMessages("PT5M", 99, Any, out CurrentTime, out NotificationMessages) method gives a fault error.
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesRequest</a:Action>
<a:MessageID>urn:uuid:9e28fea7-541f-450e-8ad0-01a210f76aa9</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPozBB+X6a8MJEsKScTDAWhKsAAAAAJ3lo8k+wp0CaILCjmW72gQ39eqv52SBMteWBucAF600ACQAA</VsDebuggerCausalityData>
<Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-IYP/hqttMbWUf7ljIMnByJQv96x2VxajSEnVHBKfLyo=">
<wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">o3Nrz8F+V7kLjMunS/JBQKhu5xg=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">PxtFP2k/Pz8/P2g/Pz8/Bz8=</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2015-03-02T19:03:36.894Z</wsu:Created>
</wsse:UsernameToken>
</Security>
<a:To s:mustUnderstand="1">http://192.168.8.243/onvif/Subscription?Idx=57</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PullMessages xmlns="http://www.onvif.org/ver10/events/wsdl">
<Timeout>PT5M</Timeout>
<MessageLimit>99</MessageLimit>
</PullMessages>
</s:Body>
</s:Envelope>
Any help on this?
SOLUTION:
System.Xml.XmlElement[] Any = new System.Xml.XmlElement[] { };
System.DateTime CurrentTime;
System.Nullable<System.DateTime> TerminationTime;
List<MessageHeader> lstHeaders = new List<MessageHeader>() { };
var oEventClient = _session.GetEventPortTypeClient();
var oAux1 = oEventClient.CreatePullPointSubscription(
new onvif10_events.FilterType(),
"PT600S",
new onvif10_events.CreatePullPointSubscriptionSubscriptionPolicy(),
ref Any,
out CurrentTime,
out TerminationTime);
if ((oAux1.ReferenceParameters != null) && (oAux1.ReferenceParameters.Any != null))
{
foreach (System.Xml.XmlElement oXml in oAux1.ReferenceParameters.Any)
{
string strName = oXml.LocalName;
string strNS = oXml.NamespaceURI;
string strValue = oXml.InnerXml;
lstHeaders.Add(MessageHeader.CreateHeader(strName, strNS, strValue, true));
}
}
// oAux1.Address.Value -> the proxy endpoint address
// lstHeaders -> headers to add to the SOAP message of the proxy request
var oPullPointSubscriptionClient = _session.GetPullPointSubscriptionClient(oAux1.Address.Value, lstHeaders);
var oSubscriptionManagerClient = _session.GetSubscriptionManagerClient(oAux1.Address.Value, lstHeaders);
do
{
oPullPointSubscriptionClient.PullMessages("PT60S", 1024, Any, out CurrentTime, out NotificationMessages);
foreach (onvif10_events.NotificationMessageHolderType message in NotificationMessages)
{
/// Handle message
}
var oRenewResult = oSubscriptionManagerClient.Renew(new LIB.Cameras.ONVIF_WS.onvif10_events.Renew() { TerminationTime = "PT600S" });
} while (_session != null);
oSubscriptionManagerClient.Unsubscribe(new onvif10_events.Unsubscribe());

OK.
The "TO" header is to ignore.
The PullPointSubscriptionClient proxy endpoint URL is the subscription "Address.Value" (and not the "TO" url).

Related

Consuming asmx Service in .net core project throws System.ServiceModel.FaultException: 'A security error was encountered when verifying the message'

I need to invoke a service which is soap and works fin in SoapUI but when I call it in my code (.Net 6.0) it throws the following exception:
System.ServiceModel.FaultException: 'A security error was encountered when verifying the message'
SOAP UI request which works fine is as follows:
<soap:Envelope xmlns:foo="http://foo.co/" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-977AECD477F913B98A16653025315882">
<wsse:Username>FooPass</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">88943205</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">+Y/Fjg0nj5vnnvJel+rSwg==</wsse:Nonce>
<wsu:Created>2022-10-09T08:02:11.588Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp wsu:Id="TS-977AECD477F913B76A16653025292951">
<wsu:Created>2022-10-09T08:02:09.292Z</wsu:Created>
<wsu:Expires>2022-10-09T08:03:09.292Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<foo:getTransactionByDate>
<foo:TerminalId>323232</foo:TerminalId>
<foo:FromDate>20220905</foo:FromDate>
<foo:ToDate>20220906</foo:ToDate>
</foo:getTransactionByDate>
</soap:Body>
</soap:Envelope>
C# code that throws exception:
BasicHttpsBinding basicHttpBinding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType
= HttpClientCredentialType.Basic;
var service = new TransactionServiceClient(basicHttpBinding,
new EndpointAddress(url));
service.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck
};
service.ClientCredentials.UserName.UserName = MyUsername;
service.ClientCredentials.UserName.Password = MyPassword;
var result = await service.getTransactionByDateAsync(_terminalCode, _fromDate, _toDate);
Please give me hint to solve it!

Overwrite WS-Adressing-Header (to and Action)

i have to access an SOAP-service with WS-Adressing. I simply imported the WSDL i got and i try to connect. But the Service is not happy with the generated WS-Adressing Headers.
My code looks like this:
var binding = new WSHttpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var entpointAddr = new EndpointAddress("https://endpoint123/services");
using (var client = new DocumentManagementServicePortTypeClient(binding, entpointAddr))
{
client.ClientCredentials?.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "123123123");
try
{
var result = client.TestFunction();
Console.WriteLine(result);
}
catch (Exception exc)
{
Console.WriteLine($"Error: {exc.Message}");
}
}
This generate a Request like this:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1"/>
<a:MessageID>urn:uuid:8123d133-c107-44cf-97be-762014fa1b83</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://endpoint123/services</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TestFunction xmlns = "http://xmldefs...../" />
</ s:Body>
</s:Envelope>
The Server has two problems with this request:
a:To is pointed to the Endpoint
a:Action is empty
The a:To is pointed to the endpoint i set in my code-snippet. But the server expected the Endpoint defined in the WSDL (a WS:\\ uri). How could i tell WCF to use the WS:\\-Link? Or could i overwrite it manually?
I could solve the problem with the a:Action by manually adding the path in the Reference.cs, for every function i like to use, but why it is not self generated?

how to select FaultContractAtribute based on Name parameter

I have to implement interface that generates two different SystemFaults
Interface:
[ServiceContract]
public interface IErrorProvider
{
[OperationContract(Action = "getError")]
[FaultContractAttribute(typeof(string), Action = "getError", Name = "Error1Fault")]
[FaultContractAttribute(typeof(string), Action = "getError", Name = "Error2Fault")]
string getError(int iArg);
}
And implementation:
Code:
public class ErrorProvider : IErrorProvider
{
public getError(int iArg)
{
if(iArg == 1)
throw new FaultException<string>("Error1Fault","you asked err 1");
if(iArg == 2)
throw new FaultException<string>("Error2Fault","you asked err 2");
return "No error";
}
}
now when I call this service, with
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<getError xmlns="http://tempuri.org/">
<iArg>1</iArg>
</getError>
</Body>
</Envelope>
I get Response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="fi-FI">you asked err 1</faultstring>
<detail>
<Error2Fault xmlns="http://tempuri.org/">Error1Fault</Error2Fault>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
It shows clearly that first throw is used. What I need to get is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="fi-FI">you asked err 1</faultstring>
<detail>
<Error1Fault xmlns="http://tempuri.org/">Error1Fault</Error1Fault>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
How to get that? And I don't have opportunity to change the other party, so somehow I need to solve this, really newbie question but I cannot find a real solution. All documents tell me to throw self made objects but I cannot understand how that's going to help as these are just error strings.

wcf service datacontract last property not added

I'm adding a property to my model with an enum.
public class ChildCareCentreEntryReservation : BasketItem, ILockableBasketItem
{
....
[DataMember]
public ChildCareCentreEntryReservationStatusTypes ChildCareCentreEntryReservationStatusType { get; set; }
}
[DataContract(Namespace = Constants.Namespace)]
public enum ChildCareCentreEntryReservationStatusTypes
{
[EnumMember]
VoorlopigIngeschreven = 0,
[EnumMember]
DefinitiefIngeschreven = 1,
[EnumMember]
Geannuleerd = 2
}
In my form I Create a ChildCareCentreEntryReservation object:
var reservation = new ChildCareCentreEntryReservation();
reservation.ChildCareEntryPeriodId = _entryPeriod.Id;
reservation.ChildCareCentreId = _centre.Id;
reservation.PersonId = _person.Id;
reservation.Comment = txtComment.Text;
reservation.ChildCareCentreEntryReservationStatusType = (ChildCareCentreEntryReservationStatusTypes)cboStatusName.SelectedIndex;
I add the ChildCareCentreEntryReservation object to a list:
var basketItems = new List<BasketItem> { reservation };
Then I send an array to the service by calling the function LockBasketItems:
LockBasketResult lockBasketResult = Service.LockBasketItems(basketItems.ToArray(), Context);
Everything builds and works correctly but my service doesn't receive my last added property.
Fiddler inspectors result (client request to service):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BasketItems xmlns="http://www./">
<BasketItem xsi:type="ChildCareCentreEntryReservation">
<RuleNamesToIgnore xsi:nil="true"/>
<ChildCareEntryPeriodId>13ccefb3-f1e4-4f64-8fb8-b07cf30d2fca</ChildCareEntryPeriodId>
<ChildCareCentreId>8cc85f37-da5d-46c5-9bb4-d6efa8448176</ChildCareCentreId>
<PersonId>56e341bb-ac05-40dc-a39a-082ae4ff087e</PersonId>
<ChildCareCentrePeriodIds>
<guid xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">61c43967-8781-4d83-a117-963c5734491f</guid>
</ChildCareCentrePeriodIds>
<LockTicket xsi:nil="true"/>
<Comment/>
<PeriodOptions xsi:nil="true"/>
</BasketItem>
</BasketItems>
<Context xmlns="http://www./">
<Language>NL</Language>
<ShopId>00000000-0000-0000-0000-000000000550</ShopId>
<SessionId>de824345-14f3-44c7-99fd-f9a073e9b51b</SessionId>
</Context>
Fiddler inspectors result (service response to client):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<ActivityId CorrelationId="d1daee11-20e2-4e98-8774-9bffe4e2e4f3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">728e68a9-17ff-44a0-b4ad-f455f403be5e</ActivityId>
</s:Header>
<s:Body>
<LockBasketResult xmlns="http://www./" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BasketItems>
<BasketItem i:type="ChildCareCentreEntryReservation">
<DivisionId>00000000-0000-0000-0000-000000000000</DivisionId>
<Id>00000000-0000-0000-0000-000000000000</Id>
<Quantity>1</Quantity>
<RuleNamesToIgnore xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<UnitPrice>0</UnitPrice>
<ChildCareEntryPeriodId>13ccefb3-f1e4-4f64-8fb8-b07cf30d2fca</ChildCareEntryPeriodId>
<ChildCareCentreId>8cc85f37-da5d-46c5-9bb4-d6efa8448176</ChildCareCentreId>
<PersonId>56e341bb-ac05-40dc-a39a-082ae4ff087e</PersonId>
<ChildCareCentrePeriodIds xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:guid>61c43967-8781-4d83-a117-963c5734491f</a:guid>
</ChildCareCentrePeriodIds>
<LockTicket i:type="ChildCareCentreEntryReservationLockTicket">
<ExpirationTime>2013-10-08T17:27:06</ExpirationTime>
<Id>13a984f8-5d97-4f87-aa52-7523849cc6f5</Id>
</LockTicket>
<Comment/>
<PeriodOptions xmlns:a="http://schemas.datacontract.org/"/>
<ChildCareCentreEntryReservationStatusType>VoorlopigIngeschreven</ChildCareCentreEntryReservationStatusType>
</BasketItem>
</BasketItems>
<IsLocked>true</IsLocked>
<ValidationResult i:nil="true"/>
</LockBasketResult>
In my Reference.cs i'm seeing the property is correctly added.
Any idea what i am missing?
I'm using ASP.NET
Solution
I had to set ChildCareCentreEntryReservationStatusTypeSpecified to true
reservation.ChildCareCentreEntryReservationStatusTypeSpecified = true;
Solved
I had to set ChildCareCentreEntryReservationStatusTypeSpecified to true
reservation.ChildCareCentreEntryReservationStatusTypeSpecified = true;

How do I retrieve values from this XML response in C# for winforms

Here is the XML response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="somehttp..">
<soap:Body>
<get4GAddressResponse xmlns="http://somelink/">
<get4GCAddressResult>
<located>true</located>
<matchStatus>S</matchStatus>
<errorCode>0</errorCode>
<message>Single Address Match</message>
<addressList>
<anyType xsi:type="Address">
<street>4301 some St</street>
<city>ABC</city>
<state>TX</state>
<zip>78751</zip>
<longitude>-97.700000</longitude>
<latitude>30.308000</latitude>
<coverageTypes>
<anyType xsi:type="NetworkCoverage">
<type>4G</type>
<isCovered>false</isCovered>
</anyType>
</coverageTypes>
</anyType>
</addressList>
</get4GAddressResult>
</get4GAddressResponse>
</soap:Body>
</soap:Envelope>"
I am trying to get the values from XML element: 'isCovered'
I am able to retrieve the values from
<located>true</located>
<matchStatus>S</matchStatus>
<errorCode>0</errorCode>
<message>Single Address Match</message>
But I need value for IsCovered.
C# code:
Location result = new TestWebService.Location();
result = get4GAddress(street, city, state, zip);
if (result != null)
{
if (result.errorCode.Equals("0"))
{
locationresult = new LocationResponse();
locationresult.located = result.located;
locationresult.addressList = result.addressList;
locationresult.matchStatus = result.matchStatus;
locationresult.message = result.message;
}
}
You can use the SoapFormatter to deserialize your response stream.

Categories