Receive SMS using Twilio and asp.net Webforms - asp.net

The Twilio documentation provides a guide for asp.net MVC, but not for webforms. I am able to send an SMS message with no problem, but receiving SMS replies is where I am stuck. I have found that it is recommended for webforms users, to use a generic handler, but that is all I have so far, and I do not know how to get the information from the handler. And also, I have to give a URL to the Twilio console and I do not know what URL to give. I can put it on any of my website pages, example "mywebsite.com/??" "??" is I don't know where and how to reference my handler.
I have created the handler "message.ashx" here:
Public Class message : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Context.Response.ContentType = "application/xml"
Dim Body = Context.Request.Forms("Body")
Dim response As New Twilio.TwiML.MessagingResponse()
response.Message("You said: " & Body)
Context.Response.Write(response.ToString())
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
So the question is, now that I have this handler in place, how do I get the information on an aspx page to view? And what url do I give to Twilio console for the reply. I am using C# but the answer can be in C# or VB.NET, as I can get translated.

I was able to solve this with the help from comments above. This is Httphandler in aspx webforms. The problem was that they updated their references so having the correct word helped, such as "MessagingResponse", vs. "Twilio.TwiML.MessagingResponse". I also tried migrate my site to MVC, and got it to work with Twilio, but had other issues with the migration. Now I just need to figure out how to actually receive the text that was sent from a user. The Twilio documentation is pretty vague on a lot of things.
Public Class SmsHandler : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "application/xml"
Dim response = New MessagingResponse
response.Message("Hello World?")
context.Response.Write(response.ToString())
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class

Related

How to store and access per call data in WCF

I'm trying to set up some WCF services that are connected and pass a custom HTTP header from service to service.
That is my client call ServiceX, which calls ServiceY, which writes to the DB.
They are originally called from a Silverlight 5 client in some cases, other cases from an ASP.NET web app.
I implemented IClientMessageInspector and IDispatchMessageInspector to pass the header from service to service, and in the DispatchMessageInspector I wrote the header to an implementation of IExtension(Of OperationContext) (see below).
However, I wanted this data only to exist for the duration of the call, but it seems to be sticking around in the services under certain circumstances as I keep seeing the same header data repeated in different calls.
Ultimately, I want to be able to pass a custom header to a WCF service, persist it only while that call exists, send it to the next service in the header, and wipe out that service instance. Am I wrong in my thinking that using a PerCall WCF service setup and OperationContext is the right way to do that?
Here is my implementation of IExtension(Of OperationContext). The auditTransactionId is the thing I want to pass in the service. As well, the Current() property is where I keep seeing existing data:
Imports System.ServiceModel
Public Class CustomOperationContextExtension
Implements IExtension(Of OperationContext)
Private ReadOnly m_items As IDictionary(Of String, Object)
Private m_auditTransactionId As String
Private Sub New()
m_items = New Dictionary(Of String, Object)()
End Sub
Public ReadOnly Property Items() As IDictionary(Of String, Object)
Get
Return m_items
End Get
End Property
Public Property AuditTransactionId() As String
Get
Return m_auditTransactionId
End Get
Set(value As String)
m_auditTransactionId = value
End Set
End Property
Public Shared ReadOnly Property Current() As CustomOperationContextExtension
Get
If (OperationContext.Current IsNot Nothing) Then
Dim context As CustomOperationContextExtension = OperationContext.Current.Extensions.Find(Of CustomOperationContextExtension)()
If context Is Nothing Then
context = New CustomOperationContextExtension()
OperationContext.Current.Extensions.Add(context)
End If
Return context
End If
Return Nothing
End Get
End Property
Public Sub Attach(owner As OperationContext) Implements IExtension(Of System.ServiceModel.OperationContext).Attach
End Sub
Public Sub Detach(owner As OperationContext) Implements IExtension(Of System.ServiceModel.OperationContext).Detach
End Sub
End Class
EDIT:
When I say that data is sticking around, I mean that when I call Current in a new service call I expect the Extensions list to be empty (in the code below in the Current() property), but there is always an existing instance of CustomOperationContextExtension there already that is left over fro a previous call. I'm not sure under which circumstances this happens.

Can I modify the Request.Headers collection?

I have an ASP.NET site that uses a third-party reporting component. This component is misbehaving by throwing a NullReferenceException whenever the client browser is not specifying a User-Agent in the request headers.
It's basically an odd scenario that I'm just trying to come up with a workaround for. I do not know who/what client is not specifying a User-Agent, which seems like bad form IMO, but we have to deal with the exceptions it is generating. I have logged a support ticket with the third-party regarding the bug in their reporting component, but I have my doubts about how fruitful that route is going to be. So my thought was just to detect when the User-Agent is blank and default it to something just to appease the reporting component. However, I can't seem to change anything in the Request.Headers collection. I get the following exception:
Operation is not supported on this platform.
I'm starting to believe I'm not going to be able to do this. I understand why ASP.NET wouldn't allow this, but I haven't come up with any other workaround.
Update: At penfold's suggestion, I tried to add the User-Agent to the Request.Headers collection using an HttpModule. This got it added to the Headers collection, but did nothing to update the Request.UserAgent property, which is what is causing the reporting component to fail. I've been looking through .NET Reflector to determine how that property is set so that I can update it, but I haven't come up with anything yet (there isn't just a private field that drives the property that I can find).
Recently I also facing similar problem same as you. I overcome the problem
of Request.UserAgent by using a mock HttpWorkerRequest.
(Assuming you already solve the agent string in Request.Headers with custom HttpModule)
Here is the sample code:
Friend Class MockedRequestWorker
Inherits HttpWorkerRequest
Private ReadOnly _BaseHttpWorkerRequest As HttpWorkerRequest
Private ReadOnly _UserAgent As String
Friend Sub New(ByVal base As HttpWorkerRequest,
ByVal UserAgent As String)
_BaseHttpWorkerRequest = base
_UserAgent = UserAgent
End Sub
Public Overrides Sub EndOfRequest()
_BaseHttpWorkerRequest.EndOfRequest()
End Sub
Public Overrides Sub FlushResponse(ByVal finalFlush As Boolean)
_BaseHttpWorkerRequest.FlushResponse(finalFlush)
End Sub
'Note: remember to override all other virtual functions by direct invoke functions
'from _BaseHttpWorkerRequest, except the following function
Public Overrides Function GetKnownRequestHeader(ByVal index As Integer) As String
'if user is requesting the user agent value, we return the
'override user agent string
If index = HttpWorkerRequest.HeaderUserAgent Then
Return _UserAgent
End If
Return _BaseHttpWorkerRequest.GetKnownRequestHeader(index)
End Function
End Class
then, in your custom HttpApplication.BeginRequest handler, do this
Private Sub BeginRequestHandler(ByVal sender As Object, ByVal e As EventArgs)
Dim request As HttpRequest = HttpRequest.Current.Request
Dim HttpRequest_wrField As FieldInfo = GetType(HttpRequest).GetField("_wr", BindingFlags.Instance Or BindingFlags.NonPublic)
Dim ua As String = "your agent string here"
Dim _wr As HttpWorkerRequest = HttpRequest_wrField.GetValue(request)
Dim mock As New MockedRequestWorker(_wr, ua)
'Replace the internal field with our mocked instance
HttpRequest_wrField.SetValue(request, mock)
End Sub
Note: this method still does not replace the user agent value in ServerVariables, but it should able to solve what you need(and my problem too)
Hope this help :)
protected void Application_BeginRequest(Object sender, EventArgs e) {
const string ua = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
Request.Headers["User-Agent"] = ua;
var httpWorkerRequestField = Request.GetType().GetField("_wr", BindingFlags.Instance | BindingFlags.NonPublic);
if (httpWorkerRequestField != null) {
var httpWorkerRequest = httpWorkerRequestField.GetValue(Request);
var knownRequestHeadersField = httpWorkerRequest.GetType().GetField("_knownRequestHeaders", BindingFlags.Instance | BindingFlags.NonPublic);
if (knownRequestHeadersField != null) {
string[] knownRequestHeaders = (string[])knownRequestHeadersField.GetValue(httpWorkerRequest);
knownRequestHeaders[39] = ua;
}
}
}
I think the best way of handling this is to use a http module that will check the header and inject the user agent if necessary.
As you have found out you cannot use the set method on the Headers object. Instead you will have to inject the user agent string into the header via protected properties that can be accessed through reflection as outlined in the answer to this question.
UPDATE
Unfortunately Request.UserAgent doesn't use the information held in Request.Headers, instead it calls the method GetKnownRequestHeader in HttpWorkerRequest. This is an abstract class and from looking at the decompiled library code the actual implementation varies depending on the hosting environment. Therefore I cannot see a way to replace the user agent string in a reliable manner via reflection. You could roll your own WorkerRequest class but for the amount of effort I don't think the payoff would be worth it.
Sorry to be negative but I think its just not possible to set the user agent within the web application in a simple manner. Your best option at the moment would be to perform a pre-check for a user agent, and if the request doesn't have one return a browser not supported error message.
You could also investigate injecting something earlier on, i.e. in IIS or at your proxy server if you use one.
Also I would recommend that this issue is reported to SAP. I know they are actively working on the Viewer at the moment and who knows they might fix it and maybe even add support for Opera!

Instantiating a class within WCF

I'm writing a WCF WebMethod to upload files to, of which I taken snippets from around the web. The WCF interface looks like this:
<ServiceContract()>
Public Interface ITransferService
<OperationContract()>
Sub UploadFile(ByVal request As RemoteFileInfo)
End Interface
<MessageContract()>
Public Class RemoteFileInfo
Implements IDisposable
<MessageHeader(MustUnderstand:=True)>
Public FileName As String
<MessageHeader(MustUnderstand:=True)>
Public Length As Long
<MessageBodyMember(Order:=1)>
Public FileByteStream As System.IO.Stream
Public Sub Dispose() Implements IDisposable.Dispose
If FileByteStream IsNot Nothing Then
FileByteStream.Close()
FileByteStream = Nothing
End If
End Sub
End Class
Within ASP.NET, when the web method is consumed, for some reason it only works when the interface is used as part of the instantiation of RemoteFileInfo:
Protected Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
If fu.HasFile Then
Dim fi As New System.IO.FileInfo(fu.PostedFile.FileName)
' this is the line in question --------------
Dim cu As ServiceReference1.ITransferService = New ServiceReference1.TransferServiceClient()
' -------------------------------------------
Dim uri As New ServiceReference1.RemoteFileInfo()
Using stream As New System.IO.FileStream(fu.PostedFile.FileName, IO.FileMode.Open, IO.FileAccess.Read)
uri.FileName = fu.FileName
uri.Length = fi.Length
uri.FileByteStream = stream
cu.UploadFile(uri)
End Using
End If
End Sub
Can anyone advise why it is not possible to create an instance of TransferService using the following approach:
Dim cu As New ServiceReference1.TransferServiceClient()
If I try the above, it breaks this line:
cu.UploadFile(uri)
...and UploadFile must be called with three parameters (FileName, Length, FileByteStream) even there is no method that uses this signature.
Why is the Interface required when creating an instance of this class please?
When you create the proxy for your service with the "Add Service Reference" dialog, by default the proxy creation code will "unwrap" message contracts, like the one you have. If you want the message contract to appear as you defined on the server side on your proxy, you need to select the "Advanced" tab, and check the "Always generate message contracts" option. With that you'll get the message contract in your client as well.
The issue is that when a MessageContract is encountered as a parameter, the WCF client generation assumes by default that you want to implement a messaging-style interface, and provides the discrete properties from the message contract as part of the client-side interface.
The Using Messaging Contracts article in MSDN contains a very detailed description of what can be done with a messaging contract and I suspect that Microsoft chose this default behavior because of some of the "games" that you can play with the messages.
However, if you examine the code generated for your UploadFile on the client side, there are some interesting tidbits that help to explain what is going on.
The first is the comments for the UploadFile method in the interface:
'CODEGEN: Generating message contract since the operation UploadFile is neither RPC nor document wrapped.
...
Function UploadFile(ByVal request As ServiceReference1.RemoteFileInfo) As ServiceReference1.UploadFileResponse
This implies that the contract would have been generated differently if the message contract had a different implementation.
The second is that you will see that there is nothing special about the code that is used to actually make the service call:
Public Sub UploadFile(ByVal FileName As String, ByVal Length As Long, ByVal FileByteStream As System.IO.Stream)
Dim inValue As ServiceReference1.RemoteFileInfo = New ServiceReference1.RemoteFileInfo()
inValue.FileName = FileName
inValue.Length = Length
inValue.FileByteStream = FileByteStream
Dim retVal As ServiceReference1.UploadFileResponse = CType(Me,ServiceReference1.ITransferService).UploadFile(inValue)
End Sub
So in this case, your code is doing exactly what the generated code does. However, if the MessageContract were more complex, I suspect that this would no longer be the case.
So, for your question:
Can anyone advise why it is not possible to create an instance of
TransferService using the following approach...
There is no reason not to take this approach as long as you verify that the implementation of the method call is functionality equivalent to your code.
There are a couple of options for changing the default generation of the method in the client:
1) Remove the MessageContract attribute from the RemoteFileInfo class.
2) Although it seems to be counter-intuitive, you can check the Always generate message contracts checkbox in the Configure Service Reference Dialog Box.

Get Domain Name using asp.net in Generic handler page

I want to get domain name not for remote ip. i have two domain(website). example www.a1.com and www.a2.com. in a2 domain send a request to a1 domain's page like GetRequest.ashx
the example of http request is
http://www.a1.com/GetRequest.ashx?username=bala&password=123456
in my GetRequest.ashx page example coding
<%# WebHandler Language="VB" Class="Handler" %>
Imports System
Imports System.Web
Public Class GetRequest : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
Dim username As String = context.Request.QueryString("username")
Dim password As String = context.Request.QueryString("password")
**'//Here i need a coding to get requested domain name that is who send the request to my page**
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
i already use the following coding but not solve my problem. because it return ip address. i need domain only not for ip.
context.Request.ServerVariables("REMOTE_ADDR")
context.Request.ServerVariables("REMOTE_HOST")
Dim domain As String
Dim url As Uri = HttpContext.Current.Request.Url
domain = url.AbsoluteUri.Replace(url.PathAndQuery, String.Empty)
the variable domain contain www.a1.com but i need www.a2.com
use google analytics api to solve my problem? then how to use this api can any one explain
Page.Request.Url.Host contains the host name of the url (www.a1.com in your example)
If a request on the www.a2.com site calls a page on the www.a1.com site, the hostname will always be www.a1.com since that is the host that was used to call the page. I recommend passing a query string variable if you need to know that the request originated from www.a2.com.
You can access the request object through HttpContext, like so:
EDIT: Changed to get host name of referring URL
string host = HttpContext.Current.Request.UrlReferrer.Host;
EDIT: UrlReferrer is returning null. Alternative using HTTP_REFERER:
if (!String.IsNullOrEmpty(Request.ServerVariables["HTTP_REFERER"]))
{
Uri referringUrl = new Uri(Request.ServerVariables["HTTP_REFERER"]);
string referringHostName = referringUrl .Host;
}
Check the Referrer:
HttpContext.Current.Request.UrlReferrer.Host
Inside your code:
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
Dim username As String = context.Request.QueryString("username")
Dim password As String = context.Request.QueryString("password")
**'//Here i need a coding to get requested domain name that is who send the request to my page**
Dim domain as string = context.Request.UrlReferrer.Host
End Sub

Log4Net, ThreadContext, and Global.asax

I am working on a Log4Net configuration that will log all unhandled exceptions. I need certain properties, based on user, to be added to each log entry. I have set this up successfully in the following manner in my Application_Error event. Here is my complete global.asax
Imports log4net
Imports log4net.Config
Public Class Global_asax
Inherits System.Web.HttpApplication
'Define a static logger variable
Private Shared log As ILog = LogManager.GetLogger(GetType(Global_asax))
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' Fires when the application is started
ConfigureLogging()
End Sub
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
Dim ex As Exception = Server.GetLastError()
ThreadContext.Properties("user") = User.Identity.Name
ThreadContext.Properties("appbrowser") = String.Concat(Request.Browser.Browser, " ", Request.Browser.Version)
If TypeOf ex Is HttpUnhandledException AndAlso ex.InnerException IsNot Nothing Then
ex = ex.InnerException
End If
log.Error(ex)
ThreadContext.Properties.Clear()
End Sub
Private Sub ConfigureLogging()
Dim logFile As String = Server.MapPath("~/Log4Net.config")
log4net.Config.XmlConfigurator.ConfigureAndWatch(New System.IO.FileInfo(logFile))
log4net.GlobalContext.Properties("appname") = System.Reflection.Assembly.GetExecutingAssembly.GetName.Name
End Sub
End Class
This appears to be working fine. However, I have some questions that I am unable to answer.
Is the way that I am adding the user specific properties, via the threadcontext, correct? Will this always log the correct information, even under load? When would you use threadlogicalcontext? Is there a better way to do this?
Thanks
It is not safe to load request-specific values into ThreadContext like that. The reason is that ASP.NET shared threads to service requests. It does this quite often, in fact.
You could instead use LogicalThreadContext, however that simply stores the values in Call Context, which is used for Remoting.
AFAIK there is no HttpContext specific context storage, so what you can do is instead assign a "value provider" instance as your thread context, and at runtime it will call .ToString() on this class to get the value.
public class HttpContextUserProvider
{
public override string ToString()
{
return HttpContext.Current.User.Identity.Name;
}
}
It's less than ideal, but it works.
Ben's answer is right on.
However, like some of the other users, I was still a bit lost on how to proceed. This log4net Context problems with ASP.Net thread agility post and especially this Marek Stój's Blog - log4net Contextual Properties and ASP.NET one give some more context for the problem with some excellent code examples.
I highly recommend Marek Stój's implementation, although the ThreadContext.Properties["UserName"] needed to be replaced with ThreadContext.Properties["User"] in my case.
I added a BeginRequest method to my Logger class which I call from Application_AuthenticateRequest which loads all the relevant log4net properties.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
Logger.BeginRequest(Request);
}
And the method code:
public static void BeginRequest(System.Web.HttpRequest request)
{
if (request == null) return;
ThreadContext.Properties["ip_address"] = AdaptivePropertyProvider.Create("ip_address", IPNetworking.GetMachineNameAndIP4Address());
ThreadContext.Properties["rawUrl"] = AdaptivePropertyProvider.Create("rawUrl", request.RawUrl);
if (request.Browser != null && request.Browser.Capabilities != null)
ThreadContext.Properties["browser"] = AdaptivePropertyProvider.Create("browser", request.Browser.Capabilities[""].ToString());
if (request.IsAuthenticated && HttpContext.Current.User != null)
ThreadContext.Properties["User"] = AdaptivePropertyProvider.Create("user", HttpContext.Current.User.Identity.Name);
}
I found I had to pass in the Request object instead of using HttpContext.Current.Request within the method. Otherwise I would loose the user and authentication information. Note that the IPNetworking class is my own so you will need to provide your own method of obtaining the client IP. The AdaptivePropertyProvider class is directly from Marek Stój.

Resources