OData queries give 404 error unless I add a trailing slash - iis

I created a dummy project to test Odata in VS2015 and I was having an exactly the same issue as described in this question, and my code is largely equivalent to what is described there.
Web API 2: OData 4: Actions returning 404
Any query to a bound function gives a 404 error until you add a trailing slash. For example:
http://localhost:46092/odata/v1/Trips/Default.GetTripNameById - 404
http://localhost:46092/odata/v1/Trips/Default.GetTripNameById/ - works as expected
http://localhost:46092/odata/v1/Trips/Default.GetTripNameById(tripID=1)?$select=Name - 404
http://localhost:46092/odata/v1/Trips/Default.GetTripNameById(tripID=1)/?$select=Name - works as expected
This is not supposed to happen because Microsoft documentation never mentions that a trailing slash is required, their examples are supposed to work without them. Also, this breaks the Swagger UI which doesn't add a trailing slash and gets 404 when trying to make any query.
What could be the reason for this behaviour? How do I make it work without a slash, which seems to be the normal expected behaviour?
Here are my code snippets:
TripsController.cs:
...
[HttpGet]
public IHttpActionResult GetTripNameById(int tripID)
{
return Ok(DemoDataSources.Instance.Trips.AsQueryable().Where(t => t.ID == tripID.ToString()));
}
WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.MapODataServiceRoute("odata", "odata/v1", GetEdmModel());
DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
config.EnsureInitialized();
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Person>("People");
builder.EntitySet<Trip>("Trips");
builder.EntityType<Trip>().Collection.Function("GetTripNameById").Returns<string>().Parameter<int>("tripID");
var edmModel = builder.GetEdmModel();
return edmModel;
}

It turns out that the Web.debug.config is actually ignored by Visual Studio.
After adding this code to web.config, everything works:
<system.webServer>
<handlers>
<!-- the following line is required for correct handling of dots in URLs-->
<add name="ApiURIs-ISAPI-Integrated-4.0"
path="/odata/*"
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
<!-- end line for handling of dots-->
</handlers>
</system.webServer>

Related

MvcSiteMapProvider how to make a node match the current url

The current node is coming up null. I can't figure out how to make MvcSiteMapProvider resolve the node under this circumstance.
Here's the node it needs to match
<mvcSiteMapNode title="Policy" route="Details" typeName="Biz.ABC.ShampooMax.Policy" preservedRouteParameters="id" />
Here's the route:
routes.MapRoute(
"Details",
"Details/{id}",
new { Controller = "Object", Action = "Details" }
).RouteHandler = new ObjectRouteHandler();
The link that gets clicked:
http://localhost:36695/MyGreatWebSite/Details/121534455762071
It's hitting the route ok. Just the MvcSiteMapProvider.SiteMaps.Current.CurrentNode is null.
A null result for CurrentNode indicates the incoming request doesn't match any node in the SiteMap In your case there are 4 different problems that may be contributing to this:
The URL you are inputting http://localhost:36695/MyGreatWebSite/Details/121534455762071 does not (necessarily) match the URL pattern you specified in the route, "Details/{id}". It may if your site is hosted as an IIS application under IISROOT/MyGreatWebSite/.
Your mvcSiteMapNode doesn't specify a controller or action to match. route only acts like an additional piece of criteria (meaning only the named route will be considered in the match), but all of the parameters also need to be provided in order for there to be a match with the route.
You are passing in a custom RouteHandler, which could alter how the route matches the URL. Without seeing the code from your ObjectRouteHandler, it is impossible to tell if or how that will affect how the route matches the URL.
You have a custom attribute, typeName in your mvcSiteMapNode configuration. Unless you have specified to ignore this attribute, it will also be required in the URL to match, i.e. http://localhost:36695/MyGreatWebSite/Details/121534455762071?typeName=Biz.ABC.ShampooMax.Policy.
I recommend against using a custom RouteHandler for the purpose of matching URLs. The effect of doing so makes your incoming routes (URLs into MVC) act differently than your outgoing routes (URLs generated to link to other pages). Since MvcSiteMapProvider uses both parts of the route, it will cause URL generation problems if you only change the incoming routes without also changing the outgoing routes to match. Instead, I recommend you subclass RouteBase, where you can control both sides of the route. See this answer for an example of a custom RouteBase subclass.
However, do note that conventional routing is pretty powerful out of the box and you probably don't need to subclass RouteBase for this simple scenario.
Solution
I arrived at the answer by adding the mvc sitemap provider project into my own solution and stepping through the mvc sitemap provider code to see why my node wasn't being matched. A few things had to be changed. I fixed it by doing the following:
Mvc.sitemap
<mvcSiteMapNode title="Policy" controller="Object" action="Details" typeName="Biz.ABC.ShampootMax.Policy" preservedRouteParameters="id" roles="*"/>
RouteConfig.cs
routes.MapRoute(
name: "Details",
url: "details/{id}",
defaults: new { controller = "Object", action = "Details", typeName = "*" }
).RouteHandler = new ObjectRouteHandler();
Now at first it didn't want to work like this, but I modified the provider like so:
RouteValueDictionary.cs (added wildcard to match value)
protected virtual bool MatchesValue(string key, object value)
{
return this[key].ToString().Equals(value.ToString(), StringComparison.OrdinalIgnoreCase) || value.ToString() == "*";
}
SiteMapNode.cs (changed requestContext.RouteData.Values)
/// <summary>
/// Sets the preserved route parameters of the current request to the routeValues collection.
/// </summary>
/// <remarks>
/// This method relies on the fact that the route value collection is request cached. The
/// values written are for the current request only, after which they will be discarded.
/// </remarks>
protected virtual void PreserveRouteParameters()
{
if (this.PreservedRouteParameters.Count > 0)
{
var requestContext = this.mvcContextFactory.CreateRequestContext();
var routeDataValues = requestContext.HttpContext.Request.RequestContext.RouteData.Values;// requestContext.RouteData.Values;
I think the second modification wasn't strictly necessary because my request context wasn't cached; it would have worked if it was. I didn't know how to get it cached.
It's the first modification to make route values honor a wildcard (*) that made it work. It seems like a hack and maybe there's a built in way.
Note
Ignoring the typeName attribute with:
web.config
<add key="MvcSiteMapProvider_AttributesToIgnore" value="typeName" />
makes another node break:
Mvc.sitemap
<mvcSiteMapNode title="Policies" url="~/Home/Products/HarvestMAX/Policy/List" productType="HarvestMax" type="P" typeName="AACOBusinessModel.AACO.HarvestMax.Policy" roles="*">
so that's why I didn't do that.

Double call to action - prettyfaces - jsf

I am making a page in which I call a PrettyFaces page-load action method:
<url-mapping id="informes-perfil">
<pattern value="/informes/#{informesPerfilMB.codigo}" />
<view-id value="/faces/informes_perfil.xhtml" />
<action onPostback="false">#{informesPerfilMB.load()}</action>
</url-mapping>
For some reason, the informesPerfilMB.load() action is called twice, and the parameter value in the second call is 'null' or 'RES_NOT_FOUND'.
Here is my load method:
public void load() {
if (isPostBack) {
isPostBack = false;
try {
System.out.println(codigo);
informe = informeEJBServiceLocal.getByCodigo(codigo);
this.buscarInformeIngreso();
this.buscarInformeOtroIngreso();
} catch (EJBServiceException e) {
e.printStackTrace();
}
}
}
The isPostBack variable is initialized to false, so this should prevent the method from being called again, but for some reason it is.
This code first prints String: dcc509a6f75849b.
Then when the load is repeated, it prints this: RES_NOT_FOUND
I hope this code helps explain what is happening enough to solve my problem, Thanks.
I've seen this happen on my similar system in the past. I think it's an interaction between faces and prettyfaces with missing files. The RES_NOT_FOUND part comes from the network traffic. There's some likely faces resource (or stylesheet) that it's trying to find in libraries and when it can't, it essentially causes the browser to go to the URL /informes/RES_NOT_FOUND. For some reason, it would often find that resource if I refreshed the page and wouldn't issue a RES_NOT_FOUND URL.
First, I'd open up the page source, and you'll find RES_NOT_FOUND, likely along with the stylesheets. Given the position of it, you might be able to correlate it to the resources loaded in your xhtml files and see which one's missing. If that doesn't help, try the developer tools and see which resources are loaded and which are not. Then make sure the resource is present, deployed, and is in the correct location.
If it's not something that you can control (like a library resource), you can always make sure your setCodigo function ignores values of "RES_NOT_FOUND".
public void setCodigo(String value) {
if (!"RES_NOT_FOUND".equals(value)) {
this.codigo = value;
}
}
You may be able to modify your security or servlet-mapping settings (in WEB.XML) to prevent URLs ending in RES_NOT_FOUND from getting to the prettyfaces pages, but I don't know enough about it to do that.
First, the reason your isPostBack variable is called twice is most likely because you have two instances of the bean, not one singleton instance. There are a few reasons this could be happening:
Your bean is request scoped and multiple requests are being made to the page.
Your bean is being created multiple times by parts of your application that use it and call the load() method.
I also believe it is possible your method is being called twice because of the way you have written your EL expression (I'm not 100% sure):
<action onPostback="false">#{informesPerfilMB.load()}</action>
^^
Note the parenthesis at the end of your method expression. I believe this will force EL to evaluate the method when the expression is evaluated. Your method expression should look like this:
<action onPostback="false">#{informesPerfilMB.load}</action>
You should also check for other places in your application where this method might be called.
Please let me know if this helps.

Where to place register function for ViewControl in Platypi

I have been going through [Platypi.io/docs/getting-started/][1] but have gotten stuck at the section about adding functions to allow users to register for the demo app (https://platypi.io/docs/getting-started/allow-users-to-register)
The specific step is
Now, let's add our register function. This function will be fired whenever the plat-button is tapped or clicked. In the template, we defined our button's tap event by specifying a function in the plat-tap attribute. The function name is register, so when that button is clicked, the register function will be fired on our ViewControl. Add the register function to the view control (in public/viewcontrols/register/register.viewcontrol.ts:
register() {
this.context.error = '';
this.userRepository.register(this.context.email,
this.context.password,
this.context.firstname,
this.context.lastname)
.then((success) => {
this.navigator.navigate(HomeViewControl);
}).catch((error) => {
this.context.error = error;
});
}
Where do I add this function? If I put it in the RegisterViewControl (like [this][2]) class I get this error: error TS2094: The property 'navigator' does not exist on value of type 'RegisterViewControl'. this.navigator.navigate(HomeViewControl); Outside the class, the syntax doesn't work.
I know my way around Javascript, but am new to TypeScript. Any suggestions?
Your RegisterViewControl should be extending the BaseViewControl, and at some level it should be extending plat.ui.ViewControl. plat.ui.ViewControl has a property called navigator on it. From your error, it looks like there might be something wrong with how the RegisterViewControl is defined.
If the above solution doesn't work, could you provide the code for the entire RegisterViewControl file?
EDIT: It definitely looks like you have it correct. There is a possibility that something is wrong with the declaration .d.ts files. Try deleting the .tscache folder and then running npm install again. It might give you more useful errors.
We recently (as in yesterday) updated the framework and UI projects to deploy a different structure. It is possible that in your public/typings/tsd.d.ts you have the following references:
/// <reference path="../../node_modules/platypus/platypus.d.ts" />
/// <reference path="../../node_modules/platypusui/platypusui.d.ts" />
Double check the node_modules directories, it is possible you need to change the tsd.d.ts to the following:
/// <reference path="../../node_modules/platypus/dist/platypus.d.ts" />
/// <reference path="../../node_modules/platypusui/dist/platypusui.d.ts" />
If this is the case, you should also go into the public/common/css/main.less file and change this line:
#import "../../../node_modules/platypusui/platypus";
to this:
#import "../../../node_modules/platypusui/dist/platypus";

IIS gives 404 when MS-DOS reserved names are used in parameters values

I have an ASP.NET Web API application and I have an action that takes one string parameter, such as:
[HttpGet]
public HttpResponseMessage GetById(string id)
{
// ...
}
It is registered accordingly:
config.Routes.MapHttpRoute("Resources", "api/resources/{id}", new
{
controller = "Resources",
action = "GetById"
});
Now, when someone calls api/resources/con, IIS gives 404. Almost any other value is OK, like api/resources/something or api/resources/nothing.
We have looked over and found that none of the reserved MS-DOS Device Driver Names can be used as a parameter value.
This appears to be a global issue, since MSDN has it too:
http://msdn.microsoft.com/con
http://msdn.microsoft.com/prn
http://msdn.microsoft.com/nul
Is there any way to allow these names to be used as route parameters values?
Add this in Web.config, under system.web.
<httpRuntime relaxedUrlToFileSystemMapping="true" />

Mule security filter breaking flow

I'm completely at a loss with my knowledge gap.
Mule 3.3.1 CE. I must use that version for now.
I have a flow which works fine until I try to use a security filter with valid credentials.
The Mule code follows. It won't make much business sense as I've pared it down to the minimum that produces the problem. Normally the outbound call is in a separate flow, but I pulled it into the Main flow for the example.
If I have the security filter on the inbound endpoint commented out and execute this, I get the expected response of the logger message and the "foo" return payload.
<https:connector name="HTTPSConnector" validateConnections="true" sendBufferSize="0" receiveBufferSize="0" receiveBacklog="0" clientSoTimeout="10000" serverSoTimeout="10000" socketSoLinger="0" doc:name="HTTP\HTTPS">
<https:tls-key-store path="/opt/eai/common/keystore/EAIKeystore.jks" keyPassword="${key.password}" storePassword="${store.password}"/>
</https:connector>
<spring:beans>
<ss:authentication-manager alias="authManager">
<ss:authentication-provider>
<ss:user-service id="userService">
<ss:user name="PortalUser" password="password" authorities="ROLE_USER"/>
</ss:user-service>
</ss:authentication-provider>
</ss:authentication-manager>
</spring:beans>
<mule-ss:security-manager>
<mule-ss:delegate-security-provider name="memory-provider" delegate-ref="authManager"/>
</mule-ss:security-manager>
<flow name="Main" doc:name="Main">
<https:inbound-endpoint exchange-pattern="request-response" host="localhost" port="10029" path="sites/r.v1" mimeType="text/xml" encoding="UTF-8" connector-ref="HTTPSConnector">
<mule-ss:http-security-filter realm="mule-realm"/>
</https:inbound-endpoint>
<custom-transformer class="com.ca.eai.esb.transformer.site.StrategySplittingTransformer" doc:name="Split"/>
<collection-splitter/>
<https:outbound-endpoint exchange-pattern="request-response"
address="${https.outbound.account.sap-nameaddress}"
connector-ref="HTTPSConnector"
mimeType="text/xml" responseTimeout="${https.outbound.timeout}"/>
<logger level="INFO" message="GOT HERE"/>
<set-payload value="foo"/>
</flow>
The custom transformer is also pared down to the minimum:
#Override
public Object transformMessage( MuleMessage message, String outputEncoding )
{
MuleMessageCollection collection = new DefaultMessageCollection( message.getMuleContext() );
collection.addMessage( message );
return collection;
}
If I uncomment the security filter and pass in bad credentials, I get the expected security exception.
If, however, I pass in valid credentials, I get an exception that it can't serialize.
Root Exception stack trace:
java.io.NotSerializableException: org.apache.commons.httpclient.ContentLengthInputStream
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at java.util.concurrent.CopyOnWriteArrayList.writeObject(CopyOnWriteArrayList.java:857)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
Can someone tell me why adding a security filter causes this?
This is a bug that has been fixed in 3.4.x.
See this answer https://stackoverflow.com/a/17930063/387927 and the comments below it.

Resources