Flex prevent URL encoding of params with HTTPRequest - apache-flex

I'm trying to port an existing AJAX app to Flex, and having trouble with the encoding of parameters sent to the backend service.
When trying to perform the action of deleting a contact, the existing app performs a POST, sending the the following: (captured with firebug)
contactRequest.contacts[0].contactId=2c33ddc6012a100096326b40a501ec72
So, I create the following code:
var service:HTTPService;
function initalizeService():void
{
service = new HTTPService();
service.url = "http://someservice";
service.method = 'POST';
}
public function sendReq():void
{
var params:Object = new Object();
params['contactRequest.contacts[0].contactId'] = '2c33ddc6012a100097876b40a501ec72';
service.send(params);
}
In firebug, I see this sent out as follows:
Content-type: application/x-www-form-urlencoded
Content-length: 77
contactRequest%2Econtacts%5B0%5D%2EcontactId=2c33ddc6012a100097876b40a501ec72
Flex is URL encoding the params before sending them, and we're getting an error returned from the server.
How do I disable this encoding, and get the params sent as-is, without the URL encoding?
I feel like the contentType property should be the key - but neither of the defined values work.
Also, I've considered writing a SerializationFilter, but this seems like overkill - is there a simpler way?

Writing a SerializtionFilter seemed to do the trick:
public class MyFilter extends SerializationFilter
{
public function MyFilter()
{
super();
}
override public function serializeBody(operation:AbstractOperation, obj:Object):Object
{
var s:String = "";
var classinfo:Object = ObjectUtil.getClassInfo(obj);
for each (var p:* in classinfo.properties)
{
var val:* = obj[p];
if (val != null)
{
if (s.length > 0)
s += "&";
s += StringUtil.substitute("{0}={1}",p,val);
}
}
return s;
}
}
I'd love to know any alternative solutions that don't involve doing this though!

Related

How to post Special character tweet using asp.net API?

I m using Given below code to post the tweet on twitter. But when we upload it on the server then special character (!,:,$ etc) tweets not published on twitter. this code is working fine in the local system
string key = "";
string secret = "";
string token="";
string tokenSecret="";
try
{
string localFilename = HttpContext.Current.Server.MapPath("../images/").ToString();
using (WebClient client = new WebClient())
{
client.DownloadFile(imagePath, localFilename);
}
var service = new TweetSharp.TwitterService(key, secret);
service.AuthenticateWith(token, tokenSecret);
// Tweet wtih image
if (imagePath.Length > 0)
{
using (var stream = new FileStream(localFilename, FileMode.Open))
{
var result = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = message,
Images = new Dictionary<string, Stream> { { "name", stream } }
});
}
}
else // just message
{
var result = service.SendTweet(new SendTweetOptions
{
Status = HttpUtility.UrlEncode(message)
});
}
}
catch (Exception ex)
{
throw ex;
}
The statuses/update_with_media API endpoint is actually deprecated by Twitter and shouldn't be used (https://dev.twitter.com/rest/reference/post/statuses/update_with_media).
TweetSharp also has some issues with using this method when the tweet contains both a 'special character' AND an image (works fine with either, but not both). I don't know why and I haven't been able to fix it, it's something to do with the OAuth signature I'm pretty sure.
As a solution I suggest you use TweetMoaSharp (a fork of TweetSharp). It has been updated to support the new Twitter API's for handling media in tweets, and it will work in this situation if you use the new stuff.
Basically you upload each media item using a new UploadMedia method, and that will return you a 'media id'. You then use the normal 'SendTweet' method and provide a list of the media ids to it along with the other status details. Twitter will attach the media to the tweet when it is posted, and it will work when there are both special characters and images.
In addition to TweetMoaSharp you can use Tweetinvi with the following code:
var binary = File.ReadAllBytes(#"C:\videos\image.jpg");
var media = Upload.UploadMedia(binary);
var tweet = Tweet.PublishTweet("hello", new PublishTweetOptionalParameters
{
Medias = {media}
});

The AMF response data structure called from ExtJS is different from that called from Flex

I'm trying to use ExtJS5.1.2 as a front-end to replace Flex3 UI.
I heard that ExtJS can use AMF. I tested calling AMF from ExtJS, and it was success.
I expected it returns the same response as AMF+Flex3. But it didn't.
The response it called from ExtJS is slower and heavy than Flex.
What I tested:
Get 10000 records from Oracle DB and show it at DataGrid.
The data size:
13.1MB(ExtJS)
2.6MB(Flex3)
I saw the responses at Firebug.
The binary response is garbling, but it looks that the data structures are different.
in ExtJS5.1.2
The field names appeared every record.
POST request
������foo.getTestRecords�/1ÿÿÿÿ
����
POST response
������/1/onResult��ÿÿÿÿ�!flex.messaging.io.ArrayCollection�source
��'�modules.entity.APR361�SEQNO� APM20HSEQ�KOCHGCD�HVPNO�FGAINO�TORYOKBN�NOTE1�MSIZE3
�0�SECKBN�MSIZE2�0�MSIZE1�0�REQFL�SKSEQNO�DJKBN�1�PCLS�1�ZUBAN�GACD� HUNITNONM
�SRCLS�502�PYVPNO�0�ZBNHCNT�DSPSEQ�YOSETU�PVPUNIT� APR363SEQ�UWSID�25803�PHKADOFL
�PBANNO�SECHGCD�PGDNM�PVLIN�0�APR36SEQ�892999�PJVSEQ�BA00010G0090�ITEMKB�GKBN�LINECD
�HKS�ZAICD�PVJAN�NYCHGCD�IPRGID�PA012X�PEND�0�FVPNO�0�PSYDATBt×oÏ���MKCD�PPRKBN2
�0�PPRKBN1�0�ISEQ�893000�PPRKBN3�0�TOSOCLO2�TOSOCLO1�PGDOHCLS�TOSOCLO3�SGVJAN�2621
�UPRGID�PA014X�IDATBtø5 Î��PPRDAT2�PPRDAT1�COMKBN�BUNCNT�PPRDAT3�ICHGCD�EMORI�NXGKBN
�GAOHCLS�PPRBSU3�PPRBSU2�ITEMOPE�PVCNT�WARI�B�TIM�20151019140515920� GENCHKDAT�VISEQ
�1343�SEC�NNOTE� APR362SEQ�UCHGCD�1053�MSGGRPID�PPRBSU1� APR361SEQ�HCNT�DDAT�SYUZUJK
�HINKB�UDATBuç˯��WRKPTN�00�MCOMSEQ�LVL�MKNM�PVPNO�0� APM21HSEQ�1018811�
SKKKSEREDA�A0010�BHCLS�PXFL�PLOT�PPRBAT1�GANM�PPRBAT2�CNCOMSEQ�RGENZU�ZAINM�NOTE10
�NOTE7�NOTE6�DFLG�0�CAMKBN�NOTE9�IWSID�6102�NOTE8�TOSOPRO�NOTE3�NOTE2�PPRBAT3
�NOTE5�NOTE4�PEYDATBtãýOØ���� �modules.entity.APR361�SEQNO� APM20HSEQ�KOCHGCD�HVPNO
�FGAINO�TORYOKBN�NOTE1�MSIZE3�SECKBN�MSIZE2�MSIZE1�REQFL�SKSEQNO�DJKBN�0�PCLS
�2�ZUBAN�GACD� HUNITNONM�SRCLS�503�PYVPNO�0�ZBNHCNT�DSPSEQ�YOSETU�PVPUNIT� APR363SEQ
�1064563�UWSID�7823�PHKADOFL�PBANNO�SECHGCD�PGDNM�PVLIN�0�APR36SEQ�1064307�PJVSEQ
�BA00013G0010�ITEMKB�GKBN�LINECD�HKS�ZAICD�PVJAN�NYCHGCD�IPRGID�PA014X�PEND�0�FVPNO
�0�PSYDAT�MKCD�PPRKBN2�0�PPRKBN1�0�ISEQ�1064567�PPRKBN3�0�TOSOCLO2�TOSOCLO1�PGDOHCLS
�TOSOCLO3�SGVJAN�1123�UPRGID�PA025X�IDATBtà¨ÈÆ���PPRDAT2�PPRDAT1�COMKBN�BUNCNT�
PPRDAT3�ICHGCD�EMORI�NXGKBN�GAOHCLS�PPRBSU3�PPRBSU2�ITEMOPE�PVCNT�WARI�B�TIM�20150803092306612
� GENCHKDAT�VISEQ�1691�SEC�NNOTE� APR362SEQ�UCHGCD�EMORI�MSGGRPID�PPRBSU1� APR361SEQ
�HCNT�DDAT�SYUZUJK�HINKB�UDATBtâÙh���WRKPTN�00�MCOMSEQ�LVL�MKNM�PVPNO�0� APM21HSEQ
�1018657�
SKKKSEREDA�BHCLS�1�PXFL�PLOT�PPRBAT1�GANM�PPRBAT2�CNCOMSEQ�RGENZU�ZAINM�NOTE10
�NOTE7�NOTE6�DFLG�0�CAMKBN�NOTE9�IWSID�7447�NOTE8�TOSOPRO�NOTE3�NOTE2�PPRBAT3
�NOTE5�NOTE4�PEYDAT�� �modules.entity.APR361�SEQNO�000100� APM20HSEQ�KOCHGCD�HVPNO�
FGAINO�TORYOKBN�NOTE1�MSIZE3�0�SECKBN�MSIZE2�0�MSIZE1�0�REQFL�0�SKSEQNO�000100
�DJKBN�0�PCLS�3�ZUBAN�GACD� HUNITNONM�SRCLS�505�PYVPNO�2�ZBNHCNT�DSPSEQ�10�YOSETU
�PVPUNIT�01� APR363SEQ�UWSID�PHKADOFL�0�PBANNO�00�SECHGCD�PGDNM�æ©ç¨®åï½ï½ï½
ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï
½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï¿¥�PVLIN�1�APR36SEQ�1064307�PJVSEQ�BA00013G0010�ITEMKB�0�GKBN
�G�LINECD�HKS�ZAICD�PVJAN�999000�NYCHGCD�IPRGID�PD230S�PEND�0�FVPNO�0�PSYDAT�
MKCD�PPRKBN2�0�PPRKBN1�0�ISEQ�1064589�PPRKBN3�0�TOSOCLO2�TOSOCLO1�PGDOHCLS�0�TOSOCLO3
�SGVJAN�1123�UPRGID�IDATBtà©bV��PPRDAT2�PPRDAT1�COMKBN�BUNCNT�PPRDAT3�ICHGCD�
EMORI�NXGKBN�1�GAOHCLS�PPRBSU3�PPRBSU2�ITEMOPE�PVCNT�1�WARI�B�TIM�20150803092306612
� GENCHKDAT�VISEQ�1700�SEC�NNOTE� APR362SEQ�UCHGCD�MSGGRPID�PPRBSU1� APR361SEQ�1064569
�HCNT�0�DDAT�SYUZUJK�HINKB�UDAT�WRKPTN�00�MCOMSEQ�LVL�0�MKNM�PVPNO�0� APM21HSEQ
�1018657�
in Flex3
The field names appeared once.
POST request
�����null�/10��,
���
Oflex.messaging.messages.RemotingMessageoperation
sourcedestinationtimestamp bodymessageIdclientIdtimeToLiveheadersgetTestRecords
foo� I92F7BB91-48E7-EB8E-D6A3-B69C86CDD6D8IDD3DCC46-C0C1-F47D-8317-4163090A7318�
DSEndpoint
my-amf DSIdIDD392F8D-20AF-9878-D0A1-9BEE2CFD8DB0
POST response
�����/10/onResult��ÿÿÿÿ
Uflex.messaging.messages.AcknowledgeMessagetimestampheaders bodycorrelationIdmessageIdtimeToLive
clientIddestinationBubSr0�
Cflex.messaging.io.ArrayCollection
#+modules.entity.APR361SEQNOAPM20HSEQKOCHGCDHVPNO
FGAINOTORYOKBNNOTE1
MSIZE3
SECKBN
MSIZE2
MSIZE1REQFLSKSEQNODJKBN PCLSZUBAN GACDHUNITNONMSRCLS
PYVPNOZBNHCNT
DSPSEQ
YOSETUPVPUNITAPR363SEQUWSIDPHKADOFL
PBANNOSECHGCDPGDNMPVLINAPR36SEQ
PJVSEQ
ITEMKB GKBN
LINECDZAICDPVJANNYCHGCD
IPRGID PENDFVPNO
PSYDAT MKCDPPRKBN2PPRKBN1 ISEQPPRKBN3TOSOCLO2TOSOCLO1PGDOHCLSTOSOCLO3
SGVJAN
UPRGID IDATPPRDAT2PPRDAT1
COMKBN
BUNCNTPPRDAT3
ICHGCD
NXGKBNGAOHCLSPPRBSU3PPRBSU2ITEMOPEPVCNT WARITIMGENCHKDATVISEQSECNNOTEAPR362SEQ
UCHGCDMSGGRPIDPPRBSU1APR361SEQ HCNT DDATSYUZUJKHINKB UDAT
WRKPTNMCOMSEQLVL MKNMPVPNOAPM21HSEQSKKKSEREDABHCLS PXFL PLOTPPRBAT1 GANMPPRBAT2CNCOMSEQ
RGENZUZAINM
NOTE10NOTE7NOTE6 DFLG
CAMKBNNOTE9IWSIDNOTE8TOSOPRONOTE3NOTE2PPRBAT3NOTE5NOTE4
PEYDAT0zz1|502z25803z
892999BA00010G0090HKS
PA012XzzBt×oÏ��zz
893000z 2621
PA014XBtø5 Î�EMORIB#20151019140515920 1343 1053Buç˯�00z
1018811A0010z 6102BtãýOØ��
z2503z1064563 7823z1064307BA00013G0010zzz
z1064567z 1123
PA025XBtà¨ÈÆ��#20150803092306612 1691BtâÙh��z1018657
|z 7447
000100zzzz<z3505"1001z-æ©ç¨®åï½ï½ï½ï½ï½ï½ï½ï½
ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï½ï
½ï½ï½ï½ï½ï¿¥|*,zG
999000
PD230Szzzz1064589zz0Btà©bV�||4 17001064569z
zz8"zz 7452
000200z>zzzVz> MCM-002864#420DzC溶ãã¼ãã§ã¼ã³ãï
¼¢ï¼«ï¼´"*,z
002864Lzzzz1064590zz0Btà©b��4P1064592Rz
zSSï¼ï¼ï¼z8"zzT
The question:
In spite of both are calling same AMF, why are the responses different?
I need lightweight response like a Flex+AMF if possible.
Any help would be greatly appreciated.
I'm using Ext JS 5.1.2, BlazeDS3, Tomcat6, Adobe Flex3.4.
Updated: Nov 04 16:05(JST)
I've read the source code of Ext.direct.AmfRemotingProvider and discovered this.
if (me.binary) {
encoder = new Ext.data.amf.Encoder( {format: 0}); // AMF message sending always uses AMF0 Here!!
// encode packet
encoder.writeAmfPacket(amfHeaders, amfMessages);
request.binaryData = encoder.bytes;
request.binary = true; // Binary response
request.headers = {'Content-Type': 'application/x-amf'};
} else {
encoder = new Ext.data.amf.XmlEncoder();
// encode packet
encoder.writeAmfxRemotingPacket(amfMessages[0]);
request.xmlData = encoder.body;
}
AmfRemotingProvider uses AMF0.
To be honest, I don't understand much about what's the difference between AMF0 and AMF3.
Anyway I'm doubting there and researching how to use AMF3 from ExtJS.
The common Java code
public List<APR361> getTestRecords() throws DAOException, IOException {
List<APR361> list = new ArrayList<APR361>();
Connection c = null;
PreparedStatement ps = null;
ResultSet rs = null;
String w_sql = "";
try {
w_sql = "SELECT A.* FROM APR361 A WHERE ROWNUM<10001";
c = ConnectionHelper.getConnection();
ps = c.prepareStatement(w_sql);
rs = ps.executeQuery();
while (rs.next()) {
list.add(new APR361(
rs.getString("ISEQ"),
rs.getString("TIM"),
rs.getString("DFLG"),
rs.getString("VISEQ"),
rs.getTimestamp("IDAT"),
rs.getString("IWSID"),
rs.getString("IPRGID"),
rs.getString("ICHGCD"),
rs.getTimestamp("UDAT"),
rs.getString("UWSID"),
rs.getString("UPRGID"),
rs.getString("UCHGCD"),
rs.getTimestamp("DDAT"),
rs.getString("LINECD"),
rs.getString("APR36SEQ"),
rs.getString("PJVSEQ"),
rs.getString("SRCLS"),
rs.getString("PCLS"),
rs.getString("BHCLS"),
rs.getString("PVLIN"),
rs.getString("PVCNT"),
rs.getString("PLOT"),
rs.getString("REQFL"),
rs.getString("PXFL"),
rs.getString("DJKBN"),
rs.getString("APR362SEQ"),
rs.getString("APR361SEQ"),
rs.getString("APR363SEQ"),
rs.getString("SEQNO"),
rs.getString("SKSEQNO"),
rs.getString("DSPSEQ"),
rs.getString("HCNT"),
rs.getString("BUNCNT"),
rs.getString("PVJAN"),
rs.getString("PGDOHCLS"),
rs.getString("PGDNM"),
rs.getString("WRKPTN"),
rs.getString("APM20HSEQ"),
rs.getString("APM21HSEQ"),
rs.getString("LVL"),
rs.getString("HINKB"),
rs.getString("SGVJAN"),
rs.getString("PYVPNO"),
rs.getString("PVPUNIT"),
rs.getTimestamp("PSYDAT"),
rs.getTimestamp("PEYDAT"),
rs.getString("PHKADOFL"),
rs.getString("WARI"),
rs.getString("SEC"),
rs.getString("MSGGRPID"),
rs.getString("HVPNO"),
rs.getString("NXGKBN"),
rs.getString("GACD"),
rs.getString("GAOHCLS"),
rs.getString("GANM"),
rs.getString("PVPNO"),
rs.getString("FVPNO"),
rs.getString("PEND"),
rs.getString("PPRKBN1"),
rs.getString("PPRBAT1"),
rs.getTimestamp("PPRDAT1"),
rs.getString("PPRBSU1"),
rs.getString("PPRKBN2"),
rs.getString("PPRBAT2"),
rs.getTimestamp("PPRDAT2"),
rs.getString("PPRBSU2"),
rs.getString("PPRKBN3"),
rs.getString("PPRBAT3"),
rs.getTimestamp("PPRDAT3"),
rs.getString("PPRBSU3"),
rs.getString("ITEMKB"),
rs.getString("ZUBAN"),
rs.getString("MKCD"),
rs.getString("MKNM"),
rs.getString("ZAICD"),
rs.getString("ZAINM"),
rs.getString("SECKBN"),
rs.getString("MSIZE1"),
rs.getString("MSIZE2"),
rs.getString("MSIZE3"),
rs.getString("RGENZU"),
rs.getString("FGAINO"),
rs.getString("TORYOKBN"),
rs.getString("GKBN"),
rs.getString("PBANNO"),
rs.getString("HUNITNONM"),
rs.getString("NNOTE"),
rs.getString("SKKKSEREDA"),
rs.getTimestamp("GENCHKDAT"),
rs.getString("KOCHGCD"),
rs.getString("SECHGCD"),
rs.getString("NYCHGCD"),
rs.getString("SYUZUJK"),
rs.getString("ITEMOPE"),
rs.getString("TOSOPRO"),
rs.getString("TOSOCLO1"),
rs.getString("TOSOCLO2"),
rs.getString("TOSOCLO3"),
rs.getString("NOTE1"),
rs.getString("NOTE2"),
rs.getString("NOTE3"),
rs.getString("NOTE4"),
rs.getString("NOTE5"),
rs.getString("NOTE6"),
rs.getString("NOTE7"),
rs.getString("NOTE8"),
rs.getString("NOTE9"),
rs.getString("NOTE10"),
rs.getString("ZBNHCNT"),
rs.getString("CAMKBN"),
rs.getString("YOSETU"),
rs.getString("MCOMSEQ"),
rs.getString("CNCOMSEQ"),
rs.getString("COMKBN")
));
}
} catch (SQLException e) {
e.printStackTrace();
throw new DAOException(e);
} finally {
try {
if (rs != null) rs.close();
if (ps != null) ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
ConnectionHelper.close(c);
}
return list;
}
Call AMF from ExtJS
Ext.Direct.addProvider({
"url":"http://127.0.0.1:8400/myTestApp/messagebroker/amf", // URL for the AMFEndpoint
"type":"amfremoting",
"endpoint": "my-amf", // the name of the AMFEndpoint channel as defined in the server's services-config.xml
"binary": true, // chooses AMF encoding
"actions":{
"foo":[{ // name of the destination as defined in remoting-config.xml on the server
"name":"getTestRecords", // method name of the method to call
"len":0 // number of parameters
}]
}
});
foo.getTestRecords((function(provider, response) {
var store = Ext.getStore("baz");
store.loadData(provider);
}));
Call AMF from Flex3
public var srv: RemoteObject;
public var arrTestRecords: ArrayCollection;
public function setSRV(): void
{
srv = new RemoteObject();
srv.showBusyCursor = true;
srv.destination = "foo";
var messageUrl:String = "http://{server.name}:{server.port}/myTestApp/messagebroker/amf";
var cs:ChannelSet = new ChannelSet();
cs.addChannel( new AMFChannel("my-amf", messageUrl) );
srv.channelSet = cs;
}
public function getTest(nextfunc: Function=null): void
{
var token: AsyncToken = srv.getTestRecords();
token.addResponder(new AsyncResponder(
// on success
function(e:ResultEvent, obj:Object=null):void
{
var w_arr: ArrayCollection;
var i: int;
w_arr = new ArrayCollection();
w_arr = e.result;
arrTestRecords = new ArrayCollection();
for (i=0; i<w_arr.length; i++) {
arrTestRecords.addItem(APR361(w_arr[i]));
}
arrTestRecords.refresh();
grid.dataProvider = arrTestRecords;
},
// NG
TokenFaultEvent
));
}
Updated: Feb 02 2016 11:35(JST)
I tried to use Node.js & node-oracledb driver with gzip compression instead of using the AMF & BlazeDS.
The response data size was 900KB!
ExtJS+Node.js(900KB) vs Flex3+AMF3(2.6MB)
However the AMF3 still about 2x faster than Node.js.

Webtest with session-id in url

We have an ASP.Net site that redirects you to a url that shows a session-id. like this:
http://localhost/(S(f3rjcw45q4cqarboeme53lbx))/main.aspx
This id is unique with every request.
Is it possible to test this site using a standard visual studio 2008/2010 webtest? How can I provide the test this data?
I have to call a couple of different pages using that same id.
Yes, it is relatively easy to do this. You will need to create a coded webtest however.
In my example we have a login post that will return the url including the session string.
Just after the we yield the login post request (request3) to the enumerator I call the following.
WebTestRequest request3 = new WebTestRequest((this.Context["WebServer1"].ToString() + "/ICS/Login/English/Login.aspx"));
//more request setup code removed for clarity
yield return request3;
string responseUrl = Context.LastResponse.ResponseUri.AbsoluteUri;
string cookieUrl = GetUrlCookie(responseUrl, this.Context["WebServer1"].ToString(),"/main.aspx");
request3 = null;
Where GetUrlCookie is something like this:
public static string GetUrlCookie(string fullUrl, string webServerUrl, string afterUrlPArt)
{
string result = fullUrl.Substring(webServerUrl.Length);
result = result.Substring(0, result.Length - afterUrlPArt.Length);
return result;
}
Once you have the session cookie string, you can substitute it really easy in any subsequent urls for request/post
e.g.
WebTestRequest request4 = new WebTestRequest((this.Context["WebServer1"].ToString() + cookieUrl + "/mySecureForm.aspx"));
I apologise for my code being so rough, but it was deprecated in my project and is pulled from the first version of the codebase - and for saying it was easy :)
For any load testing, depending on your application, you may have to come up with a stored procedure to call to provide distinct login information each time the test is run.
Note, because the response url cannot be determined ahead of time, for the login post you will have to temporarily turn off the urlValidationEventHandler. To do this I store the validationruleeventhandler in a local variable:
ValidateResponseUrl validationRule1 = new ValidateResponseUrl();
urlValidationRuleEventHandler = new EventHandler<ValidationEventArgs>(validationRule1.Validate);
So can then turn it on and off as I require:
this.ValidateResponse -= urlValidationRuleEventHandler ;
this.ValidateResponse += urlValidationRuleEventHandler ;
The alternative is to code your own such as this (reflectored from the Visual Studio code and changed to be case insensitive.
class QueryLessCaseInsensitiveValidateResponseUrl : ValidateResponseUrl
{
public override void Validate(object sender, ValidationEventArgs e)
{
Uri uri;
string uriString = string.IsNullOrEmpty(e.Request.ExpectedResponseUrl) ? e.Request.Url : e.Request.ExpectedResponseUrl;
if (!Uri.TryCreate(e.Request.Url, UriKind.Absolute, out uri))
{
e.Message = "The request URL could not be parsed";
e.IsValid = false;
}
else
{
Uri uri2;
string leftPart = uri.GetLeftPart(UriPartial.Path);
if (!Uri.TryCreate(uriString, UriKind.Absolute, out uri2))
{
e.Message = "The request URL could not be parsed";
e.IsValid = false;
}
else
{
uriString = uri2.GetLeftPart(UriPartial.Path);
////this removes the query string
//uriString.Substring(0, uriString.Length - uri2.Query.Length);
Uri uritemp = new Uri(uriString);
if (uritemp.Query.Length > 0)
{
string fred = "There is a problem";
}
//changed to ignore case
if (string.Equals(leftPart, uriString, StringComparison.OrdinalIgnoreCase))
{
e.IsValid = true;
}
else
{
e.Message = string.Format("The value of the ExpectedResponseUrl property '{0}' does not equal the actual response URL '{1}'. QueryString parameters were ignored.", new object[] { uriString, leftPart });
e.IsValid = false;
}
}
}
}
}

Http Passthrough Pluggable Protocol for Firefox

How can I make an http passthrough pluggable protocol for IE work in Firefox?
Alternatively, how to develop one for Firefox? Any examples would be appreciated.
Thanks.
On Firefox, if you would like to bypass a default behavior in a "pluggable" manner, you could write an NPAPI based plugin. Let's say that the documentation is thin on this subject... but to get you started, you could consult this.
With an NPAPI plugin, you have access to the whole OS and thus are free to expose any other resources to Firefox.
Write an XPCOM object that implements nsIObserver. Then create listener for http-on-modify-request and http-on-examine-response.
var myObj = new MyObserver(); //implements nsIObserver
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(myObj "http-on-modify-request", false);
observerService.addObserver(myObj, "http-on-examine-response", false);
Write an XPCOM object that implements nsIProtocolHandler. For example, you can access local images from web pages:
const Cu = Components.utils;
const Ci = Components.interfaces;
const Cm = Components.manager;
const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");+
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
/***********************************************************
class definition
***********************************************************/
function sampleProtocol() {
// If you only need to access your component from JavaScript,
//uncomment the following line:
this.wrappedJSObject = this;
}
sampleProtocol.prototype = {
classDescription: "LocalFile sample protocol",
classID: Components.ID("{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"),
contractID: "#mozilla.org/network/protocol;1?name=x-localfile",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
//interface nsIProtocolHandler
allowPort :function(port, scheme)
{
if ((port == 80)&&(scheme == x-localfile)) {
return true;
}
else
{
return false;
}
},
newChannel: function(aURI)
{
// Just example. Implementation must parse aURI
var file = new FileUtils.File("D:\\temp\\getImage.jpg");
var uri = NetUtil.ioService.newFileURI(file);
var channel = NetUtil.ioService.newChannelFromURI(uri);
return channel;
},
newURI(aSpec, aOriginCharset, aBaseURI)
{
//URI looks like x-localfile://example.com/image1.jpg
var uri = Cc["#mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
uri.spec = aSpec;
return uri;
},
scheme: "x-localfile",
defaultPort: 80,
protocolFlags: 76
};
var components = [sampleProtocol];
if ("generateNSGetFactory" in XPCOMUtils)
var NSGetFactory = XPCOMUtils.generateNSGetFactory(components); // Firefox 4.0 and higher
else
var NSGetModule = XPCOMUtils.generateNSGetModule(components); // Firefox 3.x
Be carefull! This approach can create vulnerability

How do I get an already (basic) authenticated context to call a web service behind the same authentication?

I have a site behind basic authentication (IIS6).
Part of this site calls a web service that is also part of the site and thus behind basic authentication as well.
However, when this happens the calling code receives a 401 Authentication Error.
I've tried a couple of things, with the general recommendation being code like this:
Service.ServiceName s = new Service.ServiceName();
s.PreAuthenticate = true;
s.Credentials = System.Net.CredentialCache.DefaultCredentials;
s.Method("Test");
However, this does not seem to resolve my problem.
Any advice?
Edit
This seems to be a not uncommon issue but so far I have found no solutions.
Here is one thread on the topic.
Solution: (I am almost certain this will help someone)
See this link for the source of this solution in VB (thanks jshardy!), all I did was convert to C#.
NB: You must be using ONLY basic authentication on IIS for this to work, but it can probably be adapted. You also need to pass a Page instance in, or at least the Request.ServerVariables property (or use 'this' if called from a Page code-behind directly). I'd tidy this up and probably remove the use of references but this is a faithful translation of the original solution and you can make any amendments necessary.
public static void ServiceCall(Page p)
{
LocalServices.ServiceName s = new LocalServices.ServiceName();
s.PreAuthenticate = true; /* Not sure if required */
string username = "";
string password = "";
string domain = "";
GetBasicCredentials(p, ref username, ref password, ref domain);
s.Credentials = new NetworkCredential(username, password, domain);
s.ServiceMethod();
}
/* Converted from: http://forums.asp.net/t/1172902.aspx */
private static void GetBasicCredentials(Page p, ref string rstrUser, ref string rstrPassword, ref string rstrDomain)
{
if (p == null)
{
return;
}
rstrUser = "";
rstrPassword = "";
rstrDomain = "";
rstrUser = p.Request.ServerVariables["AUTH_USER"];
rstrPassword = p.Request.ServerVariables["AUTH_PASSWORD"];
SplitDomainUserName(rstrUser, ref rstrDomain, ref rstrUser);
/* MSDN KB article 835388
BUG: The Request.ServerVariables("AUTH_PASSWORD") object does not display certain characters from an ASPX page */
string lstrHeader = p.Request.ServerVariables["HTTP_AUTHORIZATION"];
if (!string.IsNullOrEmpty(lstrHeader) && lstrHeader.StartsWith("Basic"))
{
string lstrTicket = lstrHeader.Substring(6);
lstrTicket = System.Text.Encoding.Default.GetString(Convert.FromBase64String(lstrTicket));
rstrPassword = lstrTicket.Substring((lstrTicket.IndexOf(":") + 1));
}
/* At least on my XP Pro machine AUTH_USER is not set (probably because we're using Forms authentication
But if the password is set (either by AUTH_PASSWORD or HTTP_AUTHORIZATION)
then we can use LOGON_USER*/
if (string.IsNullOrEmpty(rstrUser) && !string.IsNullOrEmpty(rstrPassword))
{
rstrUser = p.Request.ServerVariables["LOGON_USER"];
SplitDomainUserName(rstrUser, ref rstrDomain, ref rstrUser);
}
}
/* Converted from: http://forums.asp.net/t/1172902.aspx */
private static void SplitDomainUserName(string pstrDomainUserName, ref string rstrDomainName, ref string rstrUserName)
{
rstrDomainName = "";
rstrUserName = pstrDomainUserName;
int lnSlashPos = pstrDomainUserName.IndexOf("\\");
if (lnSlashPos > 0)
{
rstrDomainName = pstrDomainUserName.Substring(0, lnSlashPos);
rstrUserName = pstrDomainUserName.Substring(lnSlashPos + 1);
}
}
The Line:
s.Credentials = System.Net.CredentialCache.DefaultCredentials();
Maybe you should try :
s.Credentials = HttpContext.Current.User.Identity;

Resources