SOAP request losing value in Integration Broker (PT8.52.14) - web-services

I've set up a document message in order to use it in a synchronous service operation. I've published this service, and I'm using SOAPui and the built-in Service Operation Tester available directly through the PeopleTools>Integration Broker>Service Utilities>Service Operation Tester menu.
My issue : When I send a request filled with some values and then look at it in the synchronous service monitor, I don't see them any more. At some point, Integration Broker flushed the values out and I cannot figure out if this is a known bug, or something in my setup which could be wrong.
Note :
Request and Response are the same message.
Every field in the document has a length and a type set.
No issue with a Non-Rowset based message
I'm using Peopletools 8.52.14
My request is the following :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:nx="http://xmlns.oracle.com/Enterprise/Tools/schemas/NX_PAC.NX_IB_PERFS_EVENT.VERSION_2a">
<soapenv:Header/>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<NX_IB_PERFS_EVENT xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/NX_PAC.NX_IB_PERFS_EVENT.VERSION_2a">
<EventName>XYZ</EventName>
<PerfsDate>2015-02-09</PerfsDate>
<AverageTiming>0.0</AverageTiming>
<NumberOfExec>0.0</NumberOfExec>
<AveragePost>0.0</AveragePost>
</NX_IB_PERFS_EVENT>
</soapenv:Body>
</soapenv:Envelope>
The incoming values EventName and PerfsDate will disappear when looking at the original incoming message in the monitor. But this is not consistent since values show up after a reboot of the PIA.
Here's the PeopleCode of my Service Operation Handler :
method OnRequest
/+ &_msg as Message +/
/+ Returns Message +/
/+ Extends/implements PS_PT:Integration:IRequestHandler.OnRequest +/
&_msg.GetDocument().GetElement("PerfsDate").value = %Date;
Return &_msg;
end-method;
I send back the request message, and just set up a date on tag PerfsDate.
In the Response message, EventName's value is empty.
Any feedback about this ?

It looks like you aren't properly retrieving values from the request message. Below is an example of how I would retrieve the values from an Integration Broker synchronous SOAP request:
method OnRequest
/+ &_msg as Message +/
/+ Returns Message +/
/+ Extends/implements PS_PT:Integration:IRequestHandler.OnRequest +/
Local XmlDoc &requestXmlDoc;
Local XmlNode &requestRootNode;
Local array of XmlNode &perfsDateNodes, &avgTimingNodes;
Local string &perfsDateStr, &avgTimingStr;
Local date &perfsDate;
Local number &avgTiming;
&requestXmlDoc = &_msg.GetXmlDoc();
&requestRootNode = &requestXmlDoc.DocumentElement;
&perfsDateNodes = &requestRootNode.GetElementsByTagName("PerfsDate");
If &perfsDateNodes.Len > 0 Then
&perfsDateStr = &perfsDateNodes[1].NodeValue;
If IsDate(&perfsDateStr) Then
&perfsDate = DateValue(&perfsDateStr);
Else
/* some error */
End-If;
Else
/* some error */
End-If;
&avgTimingNodes = &requestRootNode.GetElementsByTagName("AverageTiming");
If &avgTimingNodes.Len > 0 Then
&avgTimingStr = &avgTimingNodes[1].NodeValue;
If IsNumber(&avgTimingStr) Then
&avgTiming = Value(&avgTimingStr)
Else
/* some error */
End-If;
Else
/* some error */
End-If;
Return &This.CreateSOAPResponse(false, &avgTiming, &perfsDate, "No Error");
End-Method;
I would also create a separate method or class to create the response message.
For example:
/**
* Create a SOAP response message based on the schema of the response message
*
*/
method CreateSOAPResponse
/+ &hasError as Boolean, +/
/+ &avgTiming as Number, +/
/+ &perfsDate as Date, +/
/+ &errorMessage as String +/
/+ Returns Message +/
Local SOAPDoc &responseSOAP;
Local XmlDoc &responseXmlDoc;
Local XmlNode &resultNode;
Local Message &responseMessage;
Local string &perfsDateStr, &avgTimingStr;
If &hasError Then
/* In the event of an error condition, certain response fields should be blank. */
&avgTiming = "";
&perfsDate = "";
Else
&errorMessage = "";
End-If;
/* Convert the number and date to string for response.*/
If All(&avgTiming) Then
&avgTimingStr = NumberToString("%*.*", &avgTiming);
Else
&avgTimingStr = "";
End-If;
If All(&perfsDate) Then
&perfsDateStr = DateTimeToLocalizedString(&perfsDate, "yyyy-MM-dd");
Else
&perfsDateStr = "";
End-If;
&responseSOAP = CreateSOAPDoc();
&responseSOAP.AddEnvelope(%SOAP_Schema);
&responseSOAP.AddHeader();
&responseSOAP.AddBody();
&responseSOAP.AddMethod("SERVICE_OPERATION NAME", 0);
&resultNode = &responseSOAP.MethodNode;
&resultNode.AddAttribute("xmlns:tns", "NAMESPACE/RESPONSE_MESSAGE_NAME");
&responseSOAP.AddParm("errorMessage", &errorMessage);
&responseSOAP.AddParm("AverageTiming", &avgTimingStr);
&responseSOAP.AddParm("PerfsDate", &perfsDateStr);
&responseMessage = CreateMessage(Operation.OPERATION_NAME_HERE, %IntBroker_Response);
&responseMessage.SetXmlDoc(&responseSOAP.XmlDoc);
Return &responseMessage;
end-method;
Hope that helps.

Related

Receiving SOAP notifications from eBay api into ASP variable?

I am trying to receive ebay api transaction notifications into an ASP hosted on a web server. The notifications are sent as SOAP messages and can be sent to a URL with a query string. Notifications must be responded to with HTTP 200 OK. I would like the notification to land inside a variable so that I can parse it and send it on to the next part of the system.
http://developer.ebay.com/DevZone/guides/ebayfeatures/Notifications/Notifications.html#ReceivingPlatformNotifications
In the documentation they mention that this is possible, but the sample they give goes the route of subscribing to an email server. This ASP would not necessarily need to make SOAP requests, just accept SOAP messages from the ebay servers.
I am studying ASP, SOAP, and query strings, but a little guidance would be truly appreciated. Thanks!
This should be pretty straight forward, your Classic ASP page becomes the endpoint for the eBay Notification API (as long as you have configured it to send notifications and what URL to send them to).
You should be able to test this with a simple Classic ASP page
<%
Dim isPost: isPost = (UCase(Request.ServerVariables("REQUEST_METHOD") & "") = "POST")
Dim hasSoapAction
'Is it a HTTP POST?
If isPost Then
'Do we have a SOAPACTION header (check both because
'it can be either HTTP_ or HEADER_ depending on IIS version)?
hasSoapAction = ( _
Len(Request.ServerVariables("HEADER_SOAPACTION") & "") > 0 Or _
Len(Request.ServerVariables("HTTP_SOAPACTION") & "") > 0 _
)
If hasSoapAction Then
'Process the notification here.
'Use Request.BinaryRead to read the SOAP
End If
'Let eBay know we have received and processing the message.
Response.Status = "200 OK"
Else
'Return method not allowed
Response.Status = "405 Method Not Allowed"
End If
Response.End
%>
You might also want to check REMOTE_HOST to make sure that you are only getting sent messages for the expected source (this isn't bulletproof though as the information can be spoofed).
Useful Links
Accessing a request's body (great existing answer that explains how to use Request.BinaryRead() to read the content and convert it to a string which you can then use in a variable or for parsing with XMLDocument.LoadXML()).
How to generate MD5 using VBScript in classic ASP? (If you want to look at a way of verifying the MD5 signature)
This is what i have so far in my notifications.asp. When I try to send it a basic SOAP post through Postman nothing is happening. Does this look like it should work?
I tested this without the If statements checking for SOAP headers, and I posted just regular string data and it works. So the binary to string conversion and output to file is all good. Now I just need to test it with actual ebay api notifications. ;-)
<%
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "iso-8859-1"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function
Dim isPost: isPost = (UCase(Request.ServerVariables("REQUEST_METHOD") & "") = "POST")
Dim hasSoapAction
'Is it a HTTP POST?
If isPost Then
'Do we have a SOAPACTION header?
hasSoapAction = (Len(Request.ServerVariables("HEADER_SOAPACTION") & "") > 0)
If hasSoapAction Then
'Process the notification here.
'Use Request.BinaryRead to read the SOAP
If Request.TotalBytes > 0 Then
Dim lngBytesCount, text
lngBytesCount = Request.TotalBytes
text = BytesToStr(Request.BinaryRead(lngBytesCount))
dim fs, tfile
set fs=Server.CreateObject("Scripting.FileSystemObject")
set tfile=fs.CreateTextFile("C:\inetpub\wwwroot\ASPtest\notifications.txt")
tfile.WriteLine(text)
tfile.Close
set tfile=nothing
set fs=nothing
End If
End If
'Let eBay know we have received and processing the message.
Response.Status = "200 OK"
Else
'Return method not allowed
Response.Status = "405 Method Not Allowed"
End If
Response.End
%>

BOBJ. RESTFull WebService API. Get list of Data Providers returns "404" message

I use RESTFull WebService API (BOBJ 4.1) to retrieve the information about the reports in the repository.
When I try to derive the list of data providers, it works file for most of the reports. However, for some of the reports I get back the "(404) not found" message. I appreciate that it's a valid response for reports which don't have any data providers, but I'm sure that the reports I get the 404 message for definitely have one or more data providers. I also don't expect it to be related to the permissions, because I don't get the "access denied" message and I can open the "problematic" reports using the Rich Client.
I use the following link:
http://{servername}:{port}/biprws/raylight/v1/documents/{reportID}/dataproviders
Has anyone experienced this kind of a problem before? Am I missing something?
I was having the same problem with some of the BO REST services (some of which went away after we rebooted our server).
You don't say which technology you're using to call the web services, but here's how you'd get the error information in a C# application.
In my C# app, below are the functions I use to call a GET & POST Business Objects 4.x REST service, and if something goes wrong, it attempts to read in the error message, so we get more than just "404 not found" or "503 Server error"...
To use these functions, you must've logged into BO and got a Login token.
protected string CallGETWebService(string URL, string token)
{
HttpWebRequest GETRequest = null;
try
{
GETRequest = (HttpWebRequest)WebRequest.Create(URL);
GETRequest.Method = "GET";
GETRequest.Accept = "application/xml";
GETRequest.Timeout = 3 * 60 * 1000; // Wait for upto 3 minutes
GETRequest.KeepAlive = false;
GETRequest.Headers.Add("X-SAP-LogonToken", token);
HttpWebResponse GETResponse = (HttpWebResponse)GETRequest.GetResponse();
Stream GETResponseStream = GETResponse.GetResponseStream();
StreamReader reader = new StreamReader(GETResponseStream);
string response = reader.ReadToEnd();
return response;
}
catch (WebException ex)
{
// If the web service throws an exception, attempt to see if it give us any clues about what went wrong.
string exception = GetExceptionMessage(URL, ex);
throw new Exception(exception);
}
}
protected string CallPOSTWebService(string URL, string token, string XMLdata)
{
try
{
// Call a "POST" web service, passing it some XML, and expecting some XML back as a Response.
byte[] formData = UTF8Encoding.UTF8.GetBytes(XMLdata);
HttpWebRequest POSTRequest = (HttpWebRequest)WebRequest.Create(URL);
POSTRequest.Method = "POST";
POSTRequest.ContentType = "application/xml";
POSTRequest.Accept = "application/xml";
POSTRequest.Timeout = 3 * 60 * 1000; // Wait for upto 3 minutes
POSTRequest.KeepAlive = false;
POSTRequest.ContentLength = formData.Length;
POSTRequest.Headers.Add("X-SAP-LogonToken", token);
Stream POSTstream = POSTRequest.GetRequestStream();
POSTstream.Write(formData, 0, formData.Length);
HttpWebResponse POSTResponse = (HttpWebResponse)POSTRequest.GetResponse();
StreamReader reader = new StreamReader(POSTResponse.GetResponseStream(), Encoding.UTF8);
string response = reader.ReadToEnd();
return response;
}
catch (WebException ex)
{
// If the web service throws an exception, attempt to see if it give us any clues about what went wrong.
string exception = GetExceptionMessage(URL, ex);
throw new Exception(exception);
}
}
protected string GetExceptionMessage(string URL, WebException ex)
{
// If one of the BO web service threw an exception, attempt to see if it give us any clues about what went wrong.
string exception = "An exception occurred whilst calling: " + URL + ", " + ex.Message;
try
{
if (ex.Response == null)
return exception;
if (ex.Response.ContentLength == 0)
return exception;
using (Stream sr = ex.Response.GetResponseStream())
{
// The web service will return a string containing XML, which we need to parse, to obtain the actual error message.
StreamReader reader = new StreamReader(sr);
string XMLResponse = reader.ReadToEnd();
XElement XML = XElement.Parse(XMLResponse);
XElement XMLException = XML.Elements().Where(e => e.Name.LocalName == "message").FirstOrDefault();
if (XMLException != null)
exception = XMLException.Value; // eg "Info object with ID 132673 not found. (RWS 000012)"
}
}
catch
{
// If the web service returned some other kind of response, don't let it crash our Exception handler !
}
return exception;
}
The important thing here is that if BO's REST services fail, the GetResponse() will throw a WebException, and we then use my GetExceptionMessage() function to check the error response (which the BO Rest Services return in XML format) and try to extract the error message from it.
Using this functionality, our C# code can throw an exception with some useful information in it:
Info object with ID 132673 not found. (RWS 000012)
..rather than just throwing a vague exception like this (which, by the way, is what all of SAP's own C# examples will do, as none include any error-handling)...
(404) Page not found
(503) Service unavailable
I've also had cases where the BO REST Services will actually throw a "(503) Service Unavailable" exception... which was completely misleading ! Again, this code will help to give us the real error message.
If BO's REST services are successful, they'll return a string containing some XML data. Let's look at some sample code showing how we'd use my functions to call the REST service to get details about a particular Webi Report.
We'll call the REST services, then convert the XML response string into an XElement, so we can obtain the Report's name from the XML.
string token = /* Your login-token */
string URL = string.Format("http://MyServer:6405/biprws/infostore/{0}", ReportID);
string WebiReportResponse = CallGETWebService(URL, token);
// Parse the web service's XML response, and obtain the name of our Webi Report
XElement ReportDetails = XElement.Parse(WebiReportResponse);
XElement title = ReportDetails.Elements().Where(e => e.Name.LocalName == "title").FirstOrDefault();
string ReportName = (title == null) ? "Unknown" : title.Value;
I thoroughly loathe the SAP documentation (and lack of it).
Life would've been MUCH easier if SAP themselves had provided some sample .Net code like this...
I've regularly had this problem in a Java routine that trawls through all WebI reports in the system to find their data-providers. At the start of the routine it works OK but as time progresses it gets slower and throws up more and more of this kind of error. I'm fairly convinced that the program itself does nothing untoward to slow down the system and it calls other BO RESTful services with no problem.
In the end I went back to getting the information using the Java SDK and it works fine. It's also much faster than Restful, even when it's working normally. Using BO 4.1 SP7

SoapUI: Using Groovy to return a MockResponse based on validation of the request

In SoapUI (and a SOAP web service), how do you evaluate a string from a request and return a response based on conditions around that request?
So far, I am able to read the values in the request and use those values in the response, but if I try to extend this to a response based on an if statement then no value is returned. Any help would be appreciated. Here is my code so far:
// create XmlHolder for request content
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
// get arguments from the request (this looks like it is all working correctly)
def FirstName = holder.getNodeValue("//FirstName")
def LastName = holder.getNodeValue("//LastName")
def Phone = holder.getNodeValue("//Phone")
def Gender = holder.getNodeValue("//Gender")
def Age = holder.getNodeValue("//Age")
//here are where the problems start
//I am using an evaluation in the if statement that should always be true
//I was trying something closer to the end solution I would like eg. if(Gender == "M")
//but this also failed to return any response
def response
if("M" == ("M")){
reponse = FirstName;
//return response
//context.setProperty("responseMessage", response)
}else
{
response = "error"
//return response
//context.setProperty("responseMessage", response)
}
return response
context.setProperty("responseMessage", response)
I have left in as comments some of the other things I have tried
Thanks
EDIT: This is within the SoapUI MockResponse, I want to set ${responseMessage} in the MockReponse as the value of the response in the XML. My objective is to send a request to the mock service and to be able to respond based on the strings contained in the request, such as whether "Gender" is "M" or "F", age is within some range etc. I feel that if my issue with the code in the question is resolved so that a value is returned, then I can solve the extended parts myself
Thanks to albciff, this has solved my problem:
...
if("M" == ("M"))
{
requestContext.responseMessage = FirstName
}else
{
requestContext.responseMessage ="error"
}
I suppose that you've the follow scenario.
You're creating a MockService in SOAPUI, inside MochService there is an operation which has a MockResponse and you dispatch your response from the operation as script. In the follow image the MockService, operation and MockResponse are shown:
So if for example you have a MockResponse with the follow content:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>${responseMessage}</soap:Body>
</soap:Envelope>
In your script to fill ${responseMessage} you have to assign the property value through requestContext object instead of setting property in the context or returning the value, in this case requestContext.responseMesssage.
In your script this could be:
...
if(Gender == "M" ){
requestContext.responseMesssage = FirstName
}else
{
requestContext.responseMesssage = "error"
}
...
You can also take a look at SOAPUI MockService documentation
Hope this helps,

WSO2 Gadget cannot access SOAP payload

I have created a data service, which tests out correctly via TryIt and SoapUI. However, when I try to include it into a Gadget, I always get this error:
"An error occurred while relaying a SOAP payload, to end point
https://data.stratoslive.wso2.com/services/t/inova8.com/ProductVendorDataService.SOAP11Endpoint/"
The gadget includes this fragment: function doSOAPCall(){ var endpoint
= "https://data.stratoslive.wso2.com/services/t/inova8.com/ProductVendorDataService.SOAP11Endpoint/"; var payload = ""; var operation = "urn:getproduct";
document.getElementById("response-disp").innerHTML =
wso2.io.makeSOAPRequest(endpoint, operation, payload); }
The data service is based on the example http://wso2.org/library/tutorials/2011/11/expose-your-cloud-data-as-rdf-data-model. Note that the operation needs no parameters, but I have tried every variant of a payload without success.
I tried your steps and found that there are two issues with your gadget code segment to do a SOAP call.
First one is,since the operation you are accessing from data service end point,do not need any payload to pass to it.Such that inside the gadget xml you have to set payload as 'null'[NOT payload=""].
Second issue is that,your defined operation name in the gadget xml is incorrect.Once I tried your data-service by try-it option,I found that your accessing operation name is "_getProduct" and it's not "getProduct".
Once corrected above two issues,SOAP gadget works well with your end point and able to get response in to gadget from your accessing operation.The corrected code segment for doSOAPCall() function is as below.
function doSOAPCall(){ var endpoint = "https://data.stratoslive.wso2.com/services/t/inova8.com/ProductVendorDataService.SOAP11Endpoint/";
var payload = null;
var operation = "urn:_getproduct";
document.getElementById("response-disp").innerHTML = wso2.io.makeSOAPRequest(endpoint, operation, payload); }
Thanks;
Lalaji

Send a push notification from a windows phone device to webservice

I have a question about the push notification service of the Windows Phone 7 device:
I can now send a push notification, using a web application to a phone, changing the data of the tile. But the problem is: when I start the app, I need to display the URI in the debugger output, and then copy-paste it inside the web application, which in turn will contact the MPNS, which is fine for an update, once to a single phone. But I want to create a webservice that can make multiple calls automatically, retrieve the URI of the application ( which changes after closing-and-opening the app, I think ) and send a push notification to it. But I haven't found an MSDN - topic that deals with this. They just use commends, saying : "to be replaced later with the URI needed." So my question is: how do I use the phone to send such a message to the webservice, respond to it, and connect to the phone again, handling such request?
and also: do I need an authenticated webservice, or is there a debug version?
This is what I have thus far :
/// <summary>
/// Setup a connection with a webservice, in order to update a shell, either a toast- or a tile shell.
/// </summary>
/// <param name="shellType">The type of shell you wish to update</param>
public void SetupShellChannel ( ShellBindType shellType )
{
//holds the push notification that is created. Since we can only have one notification channel open at any one time,
//we will need to check for existance. That is why, the channelName shouldn't be changed
HttpNotificationChannel _httpChannel = HttpNotificationChannel.Find( _channelName );
//if the _httpChannel was not found ( read: does not exist )
if ( _httpChannel == null )
{
_httpChannel = new HttpNotificationChannel( _channelName );
_httpChannel.Open( );
//because there is more than one shelltype we can open, we will use a switch to call the method we seek
BindToShell( _httpChannel, shellType );
}
//Only one push notification service is allowed per application, so we cannot send a tile notification, as well as
//a toast message notification. When we attempt this, we get a InvalidOperationException
else
{
//in this case, the _httpChannel did already exist, but the problem is, we cannot just add the eventHandlers,
//because there is the danger that it didn't exist, and we would get a null pointer exception.
//_httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>( httpChannel_ChannelUriUpdated );
//_httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>( httpChannel_ErrorOccurred );
//For testing purposes, we now display the URI to the user, and as output. Normally, we would pass this URI back to the webserver
System.Diagnostics.Debug.WriteLine( _httpChannel.ChannelUri.ToString( ) );
}
//if ( _httpChannel.ChannelUri )
//When the URI is updated, we want this to be sent to the server as well, so we know that the adress has changed,
//and don't just send data somewhere into the void. Also, when encountering an error, we want to show the user when
//an error has occured.
_httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>( HttpChannel_ChannelUriUpdated );
_httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>( HttpChannel_ErrorOccurred );
}
//here, also we would return the URI to the server, but for debugging purposes, we display them to the user.
void HttpChannel_ChannelUriUpdated( object sender, NotificationChannelUriEventArgs e )
{
Deployment.Current.Dispatcher.BeginInvoke( ( ) =>
{
System.Diagnostics.Debug.WriteLine( e.ChannelUri.ToString( ) );
MessageBox.Show( String.Format( "the URI is {0}", e.ChannelUri.ToString( ) ) );
} );
}
private void BindToShell( HttpNotificationChannel channel, ShellBindType shellType )
{
switch ( shellType )
{
case ShellBindType.BindToShellTile:
channel.BindToShellTile( );
break;
case ShellBindType.BindToShellToast:
channel.BindToShellToast( );
break;
}
}
void HttpChannel_ErrorOccurred( object sender, NotificationChannelErrorEventArgs e )
{
//getting an error would be caugth here, and then displayed to the user.
Deployment.Current.Dispatcher.BeginInvoke( ( ) =>
{
MessageBox.Show( String.Format( "A push notification {0} error occured. {1}{(2)}{3}",
e.ErrorType, e.Message, e.ErrorCode, e.ErrorAdditionalData ) );
} );
}
Ok I understand your question. What I have done is once I get teh URI from MPNS, I call a web method on a service with this as a parameter -
Subscribe(int subscriberId, Uri channelUri);
So you need to make sure you generate a subscriberId in your app to identify a user and store it in Isolated Storage. This can be a GUID.
The onus is now upon hte server to save the Subscriber to Uri mapping in persistant storage.
Also you need to provide UnSubscribe method for user to opt out of the push notification. This is one of the certification requirement for Push notifications.
Now about your second question - Yes, you would need to secure your services - you dont want to be handling with unknown requests.
What i do personally, divide it into 2 services - Publishing service and subscription service. The Publishing service will send out hte notifications while subscription will have the subscribe/unsubscribe methods.
I guess you are trying to ask that you can send push notification from Windows Phone itself or not instead using any other server side ASP/PHP like explained in Sample Applications in MSDN. Yes. You can send notifications from phone/device itself. You have to just change Send function of Sample app as given in MSDN. Reply if you have any queries.
static async Task<string> SendPushNotification(string textToSend)
{
//You can maintain a DB to query different channel URIs of devices
string subscriptionUri = "<Uri To Which You Want Send Notification>";
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
sendNotificationRequest.Method = "POST";
string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Toast>" +
"<wp:Text1>" + textToSend + "</wp:Text1>" +
"<wp:Param>/NotificationDetails.xaml?Message=" + textToSend + "</wp:Param>" +
"</wp:Toast> " +
"</wp:Notification>";
byte[] notificationMessage = Encoding.UTF8.GetBytes(toastMessage);
sendNotificationRequest.ContentLength = notificationMessage.Length;
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers["X-WindowsPhone-Target"] = "toast";
sendNotificationRequest.Headers["X-NotificationClass"] = "2";
using (var requestStream = await Task.Factory.FromAsync<Stream>(sendNotificationRequest.BeginGetRequestStream, sendNotificationRequest.EndGetRequestStream, null))
{
requestStream.Write(notificationMessage, 0, notificationMessage.Length);
}
string notificationStatus;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(sendNotificationRequest.BeginGetResponse, sendNotificationRequest.EndGetResponse, null)))
{
//StreamReader reader = new StreamReader(response.GetResponseStream());
//result = reader.ReadToEnd();
notificationStatus = response.Headers["X-NotificationStatus"];
MessageBox.Show(notificationStatus);
}
return notificationStatus;
}