how to move pages from legacy server using urlrewritefilter - tuckey-urlrewrite-filter

I am in the process of moving legacy code to a new implementation. The legacy code is hosted by a server with an "l" prefix for "legacy." As each page is moved over to the new server I want urlrewritefilter to change the url. So I need to do something like this:
from: http://lapp.company.com/page1.aspx
to: http://app.company.com/pageOne
The situation is further complicated because this needs to work on several different environments (dev, stage, production) where the server name changes slightly in each case. For example:
local: http://applocal.companydev.com:8080
dev: http://app.companydev.com
stage: http://app.companystage.com
prod: http://app.company.com
Here's an example rule:
<rule>
<from>^/offers/buyKit.aspx$</from>
<to type="redirect">%{context-path}/offers/buyKit</to>
</rule>
When http://lapp.company.com/offers/buyKit.aspx comes in, I want it to be changed to http://app.company.com/offers/buyKit
Does urlrewritefilter support this kind of thing, or am I out of luck?

Here is the solution that I came up with.
The rewrite filter allows you to specify a method that will be called when the rule is matched. I use this callback method to lookup the server context based on the current environment. This environment specific context is then set as an attribute of the request, which can be used by the "to" element of the rule.
Here is the updated rule from the xml file:
<rule>
<from>^/offers/buyKit.aspx$</from>
<run class="com.company.app.UrlHelper" method="setMyContext"/>
<to type="redirect" last="true">%{attribute:myContext}/offers/buyKit</to>
</rule>
And here is the context setting method:
public class UrlHelper {
private static final String APP_BASE_URL = "app.company.base.url";
private Properties appConfig;
public void setMyContext(HttpServletRequest request, HttpServletResponse response) throws IOException {
if (appConfig == null) {
appConfig = (Properties) StaticSpringApplicationContext.getBean("appConfig");
Assert.notNull(appConfig, "Unable to get appConfig.");
}
String appBase = appConfig.getProperty(APP_BASE_URL);
Assert.hasText(appBase, "Could not find property: " + APP_BASE_URL);
request.setAttribute("myContext", appBase);
}
}
It works quite well.

Related

Spring #RequestMapping for everything except /api/ or /rest/ (negate specific word in regex)

I need a Spring #RequestMapping that I will use to match all non-/api/... paths like /products to forward them to my / (by return "forward:/";) view controller which actually serves index.html contents and causes frontend (React) application to be served so that frontend application can handle this path to render a page.
Please note, that implicitly this #RequestMapping cannot match / as it would end up in infinite recurence and StackOverflowError. It may be worth to exclude index.html also.
In other words, I want my /api/products to be handled "locally" by Spring Boot application, where /products/ should be forwarded to render React app. There is not Apache or Nginx proxy - React app is served by Spring thanks to static resource mappings.
I have studied many similar Stackoverflow questions in this area and none of them is working.
Important note: I saw cases on Stackoverflow where the problem only supposed to be resolved, just because initially it looked like working (/products/ forwarded and /api/products handled by API Controller), but it actually wasn't, because proposed regex was matching everything and /api/products were handled only by Spring mapping precedences (more specific "wins"), but the same path would actually match the pattern if no other Controller would exist.
This results in inappropriate 404 (or mapping not found) error handling - calling any, even not existing /api/something endpoint ends up with forward to index.html in all answers that I have found, which I want to avoid. Accessing not existing /api/something endpoint should rather end up with no handler found Spring error, not in forward. An example of such solution, is the most popular one, like: #RequestMapping(value = "{_:^(?!api).*$}")
The problem is, whatever pattern I try, it ends up with forwarding all of my test cases (like /api /api/ /api/x /page/ /page/2 or none.
Just some examples of patterns I have tried:
#RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
#RequestMapping(value = "{x:^(?!api).*$}")
#RequestMapping(value = "/{path:^(?!api/).*$}")
#RequestMapping(value = "/{dataType:^.*(?!api).*$}")
#RequestMapping(value = "/{arg:(?!sitemap.xml|api|index.html).*$}")
#RequestMapping(value = "{arg:^(?!api|!index.html).*$}/**")
#RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
Looks like the original regex actually works (e.g. "{_:^(?!index\\.html|api).*$}").
The problem is, Jetty, to display 404 was internally forwarding to /error page which also was subject for that controller mapping! Effectively forwarding to frontend app from public resources instead of rendering error page
Question still valid, but for people that need solution I can propose to forward on filter level:
#Bean
public FilterRegistrationBean nonApiRequestToRootPathForwarderFilterRegistrationbean() {
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new Filter() {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request1 = (HttpServletRequest) request;
if (!request1.getRequestURI().startsWith("/api/") && !request1.getRequestURI().equals("/")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/");
requestDispatcher.forward(request, response);
return;
}
chain.doFilter(request, response);
}
});
return filterFilterRegistrationBean;
}

.net Core - HTTPS with AWS Load Balancer and Elastic Beanstalk doesn't work

I have a website that runs HTTPS correctly in my local environment. When I upload it to AWS it just times out or redirects forever.
My setup in AWS is an Elastic Beanstalk application, an RDS database running MS SQL, I added a Load Balancer to forward the HTTPS requests, and I have a SSL certificate properly assigned to the Load Balancer. From all I can tell my app is running, in fact, Entity Framework fired off and correctly built my database in my RDS instance. I just can't reach the website through the internet.
I've tried setting the Listeners different ways. If I set them like this, it just redirects forever:
If I set them like this, it just times out:
I have the default HTTP/HTTPS port forwarding code in my Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// Sets all calls to require HTTPS: https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Force all HTTP requests to redirect to HTTPS: https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
var options = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(options);
...
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto
});
...
}
I've spent days on this and I can't get it to work. I've tried taking all of my HTTPS code out and that doesn't work. I've tried code solutions from blogs like this and this and that doesn't work either. From what I've read, the Load Balancer ends up handling the HTTPS request and then forwards an HTTP request to my app. But I don't know how to properly handle that, still enforce HTTPS, and redirect HTTP to HTTPS.
This seems like it would be something that would just work out of the box without a bunch of setup from me. If it's not, I would think a lot of other people would have run into this problem by now and there'd be info about it on the internet. Am I missing something small? Because I'm totally at my wit's end about it.
If you can answer this, you'll be my new hero.
So I finally got this fixed. First, the Load Balancer has to be set to forward HTTPS 443 to HTTP 80 like this:
Then, ALL the code I've outlined in my question needs to be deleted (or not run in the AWS environment). I forgot to remove the services.Configure<MvcOptions>(options){} lines of code initially and I believe that was what was causing the error.
Then I followed this blog to handle the X-Forwarded-Proto header. I put all the code in one extension file:
public static class RedirectToProxiedHttpsExtensions
{
public static RewriteOptions AddRedirectToProxiedHttps(this RewriteOptions options)
{
options.Rules.Add(new RedirectToProxiedHttpsRule());
return options;
}
}
public class RedirectToProxiedHttpsRule : IRule
{
public virtual void ApplyRule(RewriteContext context)
{
var request = context.HttpContext.Request;
// #1) Did this request start off as HTTP?
string reqProtocol;
if (request.Headers.ContainsKey("X-Forwarded-Proto"))
{
reqProtocol = request.Headers["X-Forwarded-Proto"][0];
}
else
{
reqProtocol = (request.IsHttps ? "https" : "http");
}
// #2) If so, redirect to HTTPS equivalent
if (reqProtocol != "https")
{
var newUrl = new StringBuilder()
.Append("https://").Append(request.Host)
.Append(request.PathBase).Append(request.Path)
.Append(request.QueryString);
context.HttpContext.Response.Redirect(newUrl.ToString(), true);
}
}
}
Finally, I call this code in Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
var options = new RewriteOptions()
.AddRedirectToProxiedHttps()
.AddRedirect("(.*)/$", "$1"); // remove trailing slash
app.UseRewriter(options);
...
}
After all that it finally worked!
According to this AWS docs you must analyze X-Forwarded-Proto header and response with redirects only when it is http (not https).
Current RedirectToHttpsRule from Microsoft.AspNetCore.Rewrite package does not analyze this. You need to implement your own IRule.
app.UseForwardedHeaders() seems to have issues with AWS Load Balancers unless you clear the known networks and proxies first.
Don't forget to install the Microsoft.AspNetCore.HttpOverrides NuGet package first otherwise it will fail silently.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseForwardedHeaders(GetForwardedHeadersOptions());
...
}
private static ForwardedHeadersOptions GetForwardedHeadersOptions()
{
ForwardedHeadersOptions forwardedHeadersOptions = new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
};
forwardedHeadersOptions.KnownNetworks.Clear();
forwardedHeadersOptions.KnownProxies.Clear();
return forwardedHeadersOptions;
}
You need to accept the XForwardedProto
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
});
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseForwardedHeaders();
...
}
I was facing same issue.I finally got this fixed by changing web.config file.
Below Exact code Works for me. I follow this link. If URL rewrite module is not install then you will have to install this on your instance otherwise only this web.config file change will works.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="HTTPS rewrite behind AWS ELB rule" enabled="true" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{HTTP_X_FORWARDED_PROTO}" pattern="^http$" ignoreCase="false" />
</conditions>
<action type="Redirect" url="https://{SERVER_NAME}{URL}" redirectType="Found" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

How can I strip out part of a filename in camel XML route

I have a camel route defined in XML which picks up files in the format AB1234-20141113.txt and moves them to the ftp server. I need to rename the files in the route stripping out the date part between - and .txt so that the file on the ftp server is AB1234.txt.
As you can see from the example route definition below I have used the File Expression language in the from uri to add to the filename when moving it on the local machine after succeeding or failing but I can't see any easy way to apply a regex or substring transform using it in the ftp uri.
<route id="outboundoFtpPoller">
<from uri="file:/generatedFiles?move=done/${date:now:yyyyMMdd}/${file:name}&moveFailed=failed/${file:name.noext}-${date:now:yyyyMMddHHmmssSSS}.${file:ext}"/>
<to uri="ftp:{{ftp.server}}{{ftp.subdirectory}}/outbox/<what goes here?>" />
</route>
Any suggestions of what I can put in the section to achieve what I am trying to do would be welcome or any suggestions of how I can achieve it in a slightly different way but it must be using camel and the route definition has to remain in XML.
You can add this processor which sets the fileName using a regex before sending the file to the ftp producer
<route id="outboundoFtpPoller">
<from uri="file:/generatedFiles?move=done/${date:now:yyyyMMdd}/${file:name}&moveFailed=failed/${file:name.noext}-${date:now:yyyyMMddHHmmssSSS}.${file:ext}"/>
<bean id="myProcessor" class="mypackage.MyProcessor"/>
<to uri="ftp:{{ftp.server}}{{ftp.subdirectory}}/outbox/<what goes here?>" />
</route>
where my processor is
public class MyProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class).replaceAll("-\\d+", "");
exchange.getIn().setHeader(Exchange.FILE_NAME,fileName);
}
}
UPDATE
Without using a processor try adding this
<setHeader headerName="CamelFileName">
<simple>${in.header.CamelFileName.replaceAll("-\d+","")}</simple>
</setHeader>

ServiceStack JsonServiceClient based test fails, but service works in browser

After I got my single-page web app working (web pages served with ServiceStack's RazorFormat() MVC, not .ASP MVC), I ran a (previously passing) test for the service. The test failed. Tested the web app again (debug run, navigate to //localhost:1337/ResourceList in the browser): still working. Is something wrong with my test?
Here's the error:
Test Name: TestResourceList
Test FullName: [0-1015]ServiceWrapper.Test.TestSWrapperServices.TestResourceList
Test Source: c:\Users\uname\Documents\Visual Studio 2012\Projects\ServiceWrapper\UnitTestProject1\ServiceTests.cs : line 96
Test Outcome: Failed
Test Duration: 0:00:02.188
Result Message:
System.Net.WebException : Unable to connect to the remote server
----> System.Net.Sockets.SocketException : No connection could be made because the target machine actively refused it 127.0.0.1:1337
Result StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at ServiceStack.ServiceClient.Web.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request)
at ServiceStack.ServiceClient.Web.ServiceClientBase.Get[TResponse](IReturn`1 request)
at ServiceWrapper.Test.TestSWrapperServices.TestResourceList() in c:\Users\uname\Documents\Visual Studio 2012\Projects\ServiceWrapper\UnitTestProject1\ServiceTests.cs:line 98
--SocketException
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
Here's the test:
namespace ServiceWrapper.Test
{
[TestFixture]
public class TestSWrapperServices
{
AppHost appHost;
private const string ListeningOn = "http://*:1337/";
public const string Host = "http://localhost:1337";
private const string BaseUri = Host + "/";
[TestFixtureSetUp]
public void OnTestFixtureSetUp()
{
var appSettings = new AppSettings();
var username = Environment.GetEnvironmentVariable("USERNAME");
var userdomain = Environment.GetEnvironmentVariable("USERDOMAIN");
AppHost.AppConfig = new AppConfig(new AppSettings());
appHost = new AppHost();
// initialize Service Server
ServiceServer.SetUser(AppHost.AppConfig.UserName, AppHost.AppConfig.Password);
ServiceServer.SetLog(String.Empty);
try
{
appHost.Init();
appHost.Start(ListeningOn);
}
catch (HttpListenerException ex)
{
if (ex.ErrorCode == 5)
{
System.Diagnostics.Debug.WriteLine("You need to run the following command (as admin):");
System.Diagnostics.Debug.WriteLine(" netsh http add urlacl url={0} user={1}\\{2} listen=yes",
ListeningOn, userdomain, username);
}
else
{
System.Diagnostics.Debug.WriteLine("ERROR: {0}: {1}", ex.GetType().Name, ex.Message);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("ERROR: {0}: {1}", ex.GetType().Name, ex.Message);
}
}
[TestFixtureTearDown]
public void OnTestFixtureTearDown()
{
appHost.Dispose();
}
[Test]
public void TestResourceList()
{
JsonServiceClient client = new JsonServiceClient(BaseUri);
ResourceList response = client.Get(new ResourceList());
Assert.Contains("Some Value", response.property);
}
[Test]
}
}
I upgraded to the latest ServiceStack - 3.9.55, and it still didn't work. So, I started over again, sanity checking from the beginning. It turns out that the program.cs ListeningOn has http://*:1337/ while the nunit TestFixture ListeningOn was http://localhost:1337/
Checking urlacl (as admin) for http://localhost:1337/:
C:\Windows\system32>netsh http show urlacl url=http://localhost:1337/
URL Reservations:
-----------------
Checking urlacl (as admin) for http://*:1337/:
C:\Windows\system32>netsh http show urlacl url=http://*:1337/
URL Reservations:
-----------------
Reserved URL : http://*:1337/
User: DOMAIN\user
Listen: Yes
Delegate: No
SDDL: D:(A;;GX;;;S-1-5-21-2595267603-2801715271-1705165942-1002)
My earlier troubleshooting left the two projects with inconsistent ListeningOn values. Interestingly, using http://*:1337/ doesn't work as a wildcard url, as perhaps I had expected.
Here's a handy code snippet to help you build the add urlacl command. It also provides a useful (!) sanity check on the exact url you're listening on.
Console.WriteLine("You need to run the following command:");
Console.WriteLine(" netsh http add urlacl url={0} user={1}\\{2} listen=yes",
ListeningOn, userdomain, username);
--- Update ---
Upgrading ServiceStack eliminated the 'connection actively refused' error message. Once ListeningOn values were unified, the real
error message was exposed:
Result Message: ServiceStack.ServiceClient.Web.WebServiceException : Service Unavailable
Result StackTrace:
at ServiceStack.ServiceClient.Web.ServiceClientBase.ThrowWebServiceException[TResponse](Exception ex, String requestUri)
at ServiceStack.ServiceClient.Web.ServiceClientBase.ThrowResponseTypeException[TResponse](Object request, Exception ex, String requestUri)
at ServiceStack.ServiceClient.Web.ServiceClientBase.HandleResponseException[TResponse](Exception ex, Object request, String requestUri, Func`1 createWebRequest, Func`2 getResponse, TResponse& response)
at ServiceStack.ServiceClient.Web.ServiceClientBase.Send[TResponse](String httpMethod, String relativeOrAbsoluteUrl, Object request)
at ServiceStack.ServiceClient.Web.ServiceClientBase.Get[TResponse](IReturn`1 request)
at RemoteServerWrapper.Test.TestRSWrapperServices.TestDataList() in c:\Users\user\Documents\Visual Studio 2012\Projects\RemoteServerWrapper\UnitTestProject1\ServiceTests.cs:line 183
It's still obscure -- but at least it's not reporting something that's completely different from the real issue. So then I implemented trace in my app.config, like this:
<configuration>
<!-- ... other config settings ... -->
<system.diagnostics>
<sources>
<source name="System.Net" tracemode="includehex" maxdatasize="1024">
<listeners>
<add name="System.Net"/>
<add name="console"/>
</listeners>
</source>
<source name="System.Net.HttpListener">
<listeners>
<add name="System.Net"/>
<add name="console"/>
</listeners>
</source>
</sources>
<switches>
<add name="System.Net" value="Verbose"/>
<add name="System.Net.HttpListener" value="Verbose"/>
</switches>
<sharedListeners>
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
<add name="System.Net"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="network.log"
/>
</sharedListeners>
<trace autoflush="true"/>
</system.diagnostics>
</configuration>
Which exposed a better error message:
ERROR: [::1]:1337 Request not found: /datarequest?DataKey=some_key&startDate=20130701&endDate=20130708
OK - now I have to pull in the servicestack sources so I can step through the code and figure out why I'm getting 'Not Found' in the test, when it works when I 'debug/run' and test via the browser. Turns out that RestHandler.FindMatchingRestPath(httpMethod, pathInfo, contentType) wasn't returning a match. Humm. Why is that? The AppHost is declared identically. So, what's different?
The rest services live in my project's main assembly. When run from 'debug/run' the default assembly has the services, and everything works. But when run from the test project, with the services assembly added as a reference, servicestack can't find them. They're not in the default location, relative to the test project. So I added an AppHost class at the top of my test file, rather than relying on the one from my program.cs, and declared it as follows:
public class RSWrapperServicesAppHostHttpListener
: AppHostHttpListenerBase
{
public RSWrapperServicesAppHostHttpListener()
: base("RSWrapper Services Tests", typeof(DataRequestService).Assembly) { }
// 'DataRequestService' is a random rest service class,
// defined in the referenced services assembly
}
Now ServiceStack is happy, and my tests work again.
How did they ever work? Originally everything was jumbled together all in one project. Once I separated things into separate assemblies, i.e. DTO, Services, Business Logic and Tests, I broke it. But since I was temporarily holding off on unit tests while getting the UI working, I didn't notice right away.

Trouble with SOAP request from Flex

SUM: I ended up having to form the XML manually. I also had to create an Operation and use its send(); method rather than just doing something like WebService.MyServiceFunction(); - not sure why that was the case.
I send off the request as follows:
var xm:XML =
<SetPropertiesForCurrentUser xmlns="http://asp.net/ApplicationServices/v200">
<values xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:KeyValueOfstringanyType>
<d4p1:Key>{obj.Key}</d4p1:Key>
<d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">{obj.Value}</d4p1:Value>
</d4p1:KeyValueOfstringanyType>
</values>
</SetPropertiesForCurrentUser>;
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.loadWSDL(url);
var o:Operation = profileService.SetPropertiesForCurrentUser;
o.send(xm);
Here’s my scenario:
I have ASP.NET web services to handle authentication, user roles, and user profiles (default ASP.NET AuthenticationService, RoleService, and ProfileService, to be exact).
So from my Flex web app, I am able to successfully call the ASP.NET service. For example, something like this works fine:
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.GetAllPropertiesForCurrentUser.addEventListener("result",getAllPropertiesForCurrentUser_EventHandler);
profileService.addEventListener("fault",getAllPropertiesForCurrentUserFault_EventHandler);
profileService.loadWSDL(url);
profileService.GetAllPropertiesForCurrentUser();
I run into trouble when I need to pass a Dictionary object to another function on the service (SetPropertiesForCurrentUser). The .NET service asks for this type of value:
System.Collections.Generic.IDictionary(Of String, Object)
Here are the two pertinent entries from the web.config entry from my ASP.NET service:
<properties>
<clear/>
<add name="coordinateFormat" />
</properties>
...
<profileService enabled="true"
readAccessProperties="coordinateFormat"
writeAccessProperties="coordinateFormat"/>
So after putting together a SOAP request from a Silverlight app (which works as expected) I’ve narrowed it down to a difference in the XML request sent to the SOAP handler:
From Flex:
<tns:Value>DMS</tns:Value>
From Silverlight:
<d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">DMS</d4p1:Value>
If I take the request generated by Flex, catch it with Fiddler, modify that one line to include the “type” namespace – it works.
Anyone have an idea how I can get that namespace onto my variable that is passed to the SOAP handler from Actionscript? Here is my code for sending off that SetPropertiesForCurrentUser function:
var obj:Object = {};
obj["Key"] = "coordinateFormat";
obj["Value"] = DMS;
var profileService:WebService = new WebService();
profileService.useProxy = false;
profileService.SetPropertiesForCurrentUser.addEventListener("result",setPropertiesForCurrentUser_EventHandler);
profileService.addEventListener("fault",setPropertiesForCurrentUserFault_EventHandler);
profileService.loadWSDL(url);
profileService.SetPropertiesForCurrentUser(new ArrayCollection([obj]),false);
Thanks,
Josh
The default SOAPEncoder that is used is some what limited in its capabilities (like not including the type attribute you mentioned above). Luckily, there is a way to control that by writing your own encoder.
see this link at adobe (read part about using custom web service serialization) Link on Adobe's Site