DnnApiController and Azure Website - ajax

We have a development site on an Azure VM and production on Azure Website both using DNN Platform 7.1.2.
The Ajax calls pattern as seen below calls the DnnApicontroller and works fine on the Dev site, but fails once deployed to the production site on the Azure Website.
I've checked the Bin folder to ensure both are using the same version dlls. I have checked the webconfig files and found those to be similar too.
The error received is "{"Message":"Unable to locate a controller for http://mydomain.com/DesktopModules/ContentModule/API/BusinessObjects/HelloWorld. Searched in namespaces: IPW.Modules.ContentModule, ContentModule."}"
These call work fine on the dev site. Based on the error message, the routing didn't discover a matching controller which the namespaces provided.
-this is an example of the ajax call:
$.ajax({
type: "POST",
cache: false,
url: baseServicePath + 'HelloWorld',
dataType: "json",
beforeSend: serviceFramework.setModuleHeaders
}).done(function (data) {
console.log(data);
}).fail(function () {
console.log('Sorry failed to load hours');
});
-the 'baseServicePath' obtains URL using the DNN Platform serviceFramework.getServiceRoot('ContentModule') + 'BusinessObjects/'
-The routemapper:
public void RegisterRoutes(IMapRoute mapRouteManager) {
mapRouteManager.MapHttpRoute("ContentModule", "default", "{controller}/{action}", new[] { "My.Modules.ContentModule", "ContentModule" });
}
-and the apicontroller method:
public class BusinessObjectsController : DotNetNuke.Web.Api.DnnApiController
{
[AllowAnonymous]
[AcceptVerbs("GET", "POST")]
public HttpResponseMessage HelloWorld()
{
string result = "Hello world! Time is: " + DateTime.Now + "";
var response = Request.CreateResponse(HttpStatusCode.OK, result, Configuration.Formatters.JsonFormatter);
return response;
}
}
}
Where the call fails is on the production site which is running on an Azure Website, the code is identical to the dev. The DNN Platform is using a custom mapping interface. Any suggestions are appreciated.

I'm supposing that if you are using custom domains in the Azure Website:
You have created a DNN portal alias for the site corresponding with the custom DNS name
You have also enabled that domain host name in the Azure Website
If you are using a naked comain (like "http://mydomain.com/...") ensure that you have the correct setup (check http://maartenvanstam.wordpress.com/2013/08/23/configuring-a-naked-domain-name-for-a-windows-azure-web-site/)
If this doesn't help, just check the module example "DNN Todo List" available at GitHub at http://github.com/davidjrh/dnntodolist. Is just using the same pattern.

Related

ajax post not mapping parameters to asp.net controller action

I have this weird issue. I just switched from develoment pc (win7 to win10) and when I run my website now (in debug) the parameters being posted by an ajax call are not being mapped to the parameters on the controller action. On my old development pc it is being mapped, but on my new one it just won't do it.
this is my ajax call:
var obj = { companies: activeCompanyFilters, vesselTypes: activeVesselTypeFilters, vessels: activeVesselFilters, mapFilterType: getMapFilterType(), flushSession: flushSession };
var json = JSON.stringify(obj);
$.ajax({
type: "POST",
url: $("#filter-section").attr("data-source-link"),
data: json,
contentType: "application/json; charset=utf-8",
success: retrieveSuccess
}).done(() => {
layerChanged();
if (indicator) {
indicator.close();
}
});
this is the content being sent (captured with fiddler):
{"companies":[],"vesselTypes":[],"vessels":[2317],"mapFilterType":1,"flushSession":false}
and this is my controller:
[AjaxOnly]
public JsonResult FilterMarkers(long[] companies, long[] vesselTypes, long[] vessels, int? mapFilterType, bool? flushSession)
{
if (flushSession.HasValue && flushSession.Value)
Session["HomeSession"] = null;
MapFilterType filterType = HomeControllerHelper.CastToMapFilterTypeOrDefault(mapFilterType, GetSidUser());
var session = HomeControllerHelper.GetCurrentSession(Session, filterType);
var filtered = MapFilter.FilterData(session.VesselDetails, companies, vesselTypes, vessels).ToList();
return new JsonResult()
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
VesselDetails = filtered
}
};
}
I don't know what I'm missing. And I know it works because it works on my old pc. Is there a setting in IIS I'm missing?
I found the problem. Via visual studio you can create a virtual directory if you're using a local iis. i configured it like 'localhost/test'.
Things in the website are configured to Test.
so it was just a casing problem. Just strange only mapping failed but everything else worked

API Call From Word Web Add-In (Office.Js) Is Not Working: CORS Issue?

Friends,
I am trying to call API from Word Add-in and getting "Access Denied" error. I did some research and it looks like "Cross Origin Resource Sharing" is the cause.
1. Web API
I am hosting Web API 2 locally at "http://localhost:61546/api/ORG_NAMES"
& I have enabled CORS to accept all origins, See below WebApiConfig.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
2. Test Application
To test this API to ensure it supports CORS, I have created below page and hosted on localhost:52799/home.html, I was able to get expected response. I have tested this in IE 10 & Chrome.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function () {
var obj;
.support.cors = true;
$.getJSON("http://localhost:61546/api/ORG_NAMES/112233",
function (data) {
alert(data.ORG_ID);
});
});
});
</script>
</head>
<body>
<button>Click me</button>
</body>
3. Word Add-In
Now I wanted to call this API from my Word Web Add-In. Word Add-In running from different host https://localhost:44339/, see below code. Here getJSON returns "Access Denied".
var OrgID;
$.getJSON("http://localhost:61546/api/ORG_NAMES/112233",
function (data) {
OrgID = data.ORG_ID;
});
Also when I call API from word add-in, it's not going to fiddler.
Note: This is "Web Add-ins --> Word Add-in" project.
4. Fix - Need Help
Not sure why I am getting "Access Denied" error from Word-Add-In, if CORS is the issue then my test application (#2) shouldn't have worked, correct ?
I have tried call JSON using "$.ajax", "XMLHttpRequest" but it didn't work.I might be missing some configuration settings.
Appreciate any help here.
Let me know if you need more information.
Since it sounds like an issue within an Office Add-in only, rather than in a regular page, have you tried setting your AppDomains in the manifest file? See "Specify domains you want to open in the add-in window" in https://dev.office.com/docs/add-ins/overview/add-in-manifests
<?xml version="1.0" encoding="UTF-8"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="TaskPaneApp">
<Id>c6890c26-5bbb-40ed-a321-37f07909a2f0</Id>
<Version>1.0</Version>
<ProviderName>Contoso, Ltd</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="Northwind Traders Excel" />
<Description DefaultValue="Search Northwind Traders data from Excel"/>
<AppDomains>
<AppDomain>https://www.northwindtraders.com</AppDomain>
</AppDomains>
<DefaultSettings>
<SourceLocation DefaultValue="https://www.contoso.com/search_app/Default.aspx" />
</DefaultSettings>
<Permissions>ReadWriteDocument</Permissions>
</OfficeApp>
You will not need Jsonp if you are making Ajax calls. You will have to make sure that you all launches with HTTPS, if it is launching in HTTP it will block that traffic. Remember that office-js back bone is IE and there for; for security purposes the api will only allow HTTPS
Update
Remember that an office-js add in is actually two projects and you must make sure your projects are both launching in HTTPS. Also I would just look over the Manifest file and look at your source and make sure that is point at HTTPS
I had same issue using ajax could not call web-api.NET MVC.
Web api side(Server side):
Implement CORS in Web api because excel office.js works on diffent port and binds proxy object of server inside excel while web api are held on another port so it is as good as having 2 different domains on local so browser automatically blocks request made.
So Cross origin Resource sharing is required.
Enable Https for web apis.
http://csharp-video-tutorials.blogspot.com/2016/09/aspnet-web-api-enable-https.html
Client side
Just make call using ajax as shown below.
url: 'https://localhost:44319/api/Default/PostItems'
Note : https : is compulsory required .
function makeAjaxCall(rangeJSON) {
$.ajax({
url: 'https://localhost:44319/api/Default/PostItems',
type: 'POST',
data: rangeJSON,
contentType: 'application/json;charset=utf-8',
}).done(function (data) {
console.log(data)
app.showNotification(data.Status, data.Message);
}).fail(function (status) {
app.showNotification('Error', 'Could not communicate with the server.');
}).always(showResponse);
}
function exceltojson() {
Excel.run(function (ctx) {
var range = ctx.workbook.worksheets.getItem("Sheet1").getRange("A1:BO765");
range.load("values, numberFormat");
ctx.sync().then(
function () {
makeAjaxCall(JSON.stringify(range.values));
}).catch(function (error) {
console.log(error);
});
});
function showResponse(object) {
console.log(object);
$("#output").text(JSON.stringify(object,null, 4));
}

WebAPI : 403 Forbidden after publish website

Alright, I'm having a tough time locating the problem since it works locally but after doing a publish the results are simply:
Error Code: 403 Forbidden. The server denied the specified Uniform Resource Locator (URL). Contact the server administrator. (12202)
The code:
[RoutePrefix("api/v1/project")]
public class ProjectController : BaseApiController
{
[HttpGet]
public HttpResponseMessage GetProjects()
{
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
if(User.Identity.IsAuthenticated)
{
var model = new ModelFactory().CreateProjects();
resp = Request.CreateResponse(HttpStatusCode.OK, model);
}
return resp;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// all actions under /project routes require authentication
config.Routes.MapHttpRoute(
name: "ProjectApi",
routeTemplate: "api/v1/{controller}/{action}/{apikey}",
defaults: new { apikey = RouteParameter.Optional },
constraints: new { controller = "project" },
handler: new BasicAuthHandler(config));
// all routes requires an api key
config.MessageHandlers.Add(new ApiKeyHandler());
config.MapHttpAttributeRoutes();
}
}
I've tried several "solutions" from the net yet none of them seems to fix this. I've added the:
// Stop IIS/Asp.Net breaking our routes
RouteTable.Routes.RouteExistingFiles = true;
from: http://www.grumpydev.com/2013/09/17/403-14-error-when-trying-to-access-a-webapi-route/
And also made sure that:
<modules runAllManagedModulesForAllRequests="true">
Having the code above, using the following link gives a successful connection where it checks (in the correct order) the APIkey (ApiKeyHandler), checks if the user needs to log in(BasicAuthHandler) and then goes to method in the controller ({controller}/{action}).
// THIS WORKS!
http://localhost:51077/api/v1/project/getprojects?apikey=123456
then we do a publish and tries the same thing
// This is haunted with number 403
http://website.com/api/v1/project/getprojects?apikey=123456
gives the Error Code: 403 Forbidden.
I am clueless. I've even tried changing the whole publish folder's security settings for "NETWORK SERVICE" to full access.. no change.
Let me know if you need any more intel.
Called the web server machine fellas and they had a firewall blocking incoming webapi calls with authenticating. It now works as it should :)

Cross origin SignalR connection stops after negotiate

I have an MVC 5 app serving up views, and a Web API 2 app as the service layer (.NET 4.5). The Web API app uses SignalR 2.1.2 to return progress as it's processing POSTs to the service API. The two are deployed to different domains, so I've set up cross origin support as per the asp.net tutorial article.
[assembly: OwinStartup(typeof (Startup))]
namespace MyApp.Service
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
//worry about locking it down to specific origin later
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration());
});
//now start the WebAPI app
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
WebApiConfig.cs also contains its own CORS declaration.
namespace MyApp.Service
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//controller invocations will come from the MVC project which is deployed to a
//different domain, so must enable cross origin resource sharing
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
//Snip other controller dependency initialisation
}
}
}
I've defined a simple hub class with no server-side API (it's only to allow the server to push to the clients, not for the clients to call into).
namespace MyApp.Service.Hubs
{
[HubName("testresult")]
public class TestResultHub : Hub
{
}
}
Since I'm going cross-domain AND the hub is not exposing any server side API, I'm not bothering to use a generated JS proxy.
The relevant bits of the JS that set up the signalr hub connection is: (remember this is being served up from the MVC app, which does not have any signalr support (except jquery-signalr-{version}.js of course))
function TestScenarioHandler(signalrHubUrl) {
var self = this;
//Snip irrelevant bits (mostly Knockout initialisation)
self.signalrConnectionId = ko.observable();
var hubConnection = $.hubConnection(signalrHubUrl, { useDefaultPath: false });
var hubProxy = hubConnection.createHubProxy("testresult");
hubProxy.on("progress", function(value) {
console.log("Hooray! Got a new value from the server: " + value);
});
hubConnection.start()
.done(function() {
self.signalrConnectionId(hubConnection.id);
console.log("Connected to signalr hub with connection id " + hubConnection.id);
})
.fail(function() {
console.log("Failed to connect to signalr hub at " + hubConnection.url);
});
}
Going cross-origin like this, Firefox network traffic shows (and I've confirmed Chrome shows the same thing) a GET to
http://****service.azurewebsites.net/signalr/negotiate?clientProtocol=1.5&connectionData=[{"name":"testresult"}]&_=1424419288550
Notice that the name matches the value of the HubName attribute on my hub class.
This GET returns HTTP 200, the response gives me a JSON payload containing a ConnectionId, ConnectionToken, and a bunch of other fields that suggests everything's ok. The HTTP response also has the Access-Control-Allow-Origin: header set to the domain that the GET originated from. All up it looks good, except that's where the traffic stops.
But the JS console prints "Failed to connect to signalr hub at http://****service.azurewebsites.net/signalr"
To verify I'm not doing anything too stupid, I've added signalr support and a basic hub to the MVC app (so no cross origin required), and changed the $.hubConnection() and hubConnection.createProxy() calls accordingly. When I do that, browser traffic shows the same /signalr/negotiate?... GET (obviously not cross origin any more), but then also GETs to /signalr/connect?... and /signalr/start?.... The JS console also prints a success message.
So in summary;
CORS is enabled on the service layer, and the signalr /negotiate GET returns 200, what appears to be a valid connection id, and the expected Access-Control-Allow-Origin: header. This suggests to me that the server-side CORS support is behaving itself correctly, but the signalr connection does not succeed.
When I reconfigure so the signalr connection is NOT cross origin, everything works as expected.
WTF am I missing or doing wrong?! Some conflict between HttpConfiguration.EnableCors() and IAppBuilder.UseCors(CorsOption) perhaps?
Solved it. I had changed the map.UseCors(CorsOptions.AllowAll) to pass in a CorsPolicy object instead, and set SupportsCredentials to false, having read elsewhere that Access-Control-Allow-Origin: * is incompatible with access-control-allow-credentials: true.
private static readonly Lazy<CorsOptions> SignalrCorsOptions = new Lazy<CorsOptions>(() =>
{
return new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context =>
{
var policy = new CorsPolicy();
policy.AllowAnyOrigin = true;
policy.AllowAnyMethod = true;
policy.AllowAnyHeader = true;
policy.SupportsCredentials = false;
return Task.FromResult(policy);
}
}
};
});
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(SignalrCorsOptions.Value);
map.RunSignalR(new HubConfiguration());
});
//now start the WebAPI app
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Setting SupportCredentials to true results in the Access-Control-Allow-Origin header being rewritten with the actual origin (not *) and access-control-allow-credentials: true in the response.
And now it works.
For me following settings did good job
services.AddCors(c =>
{
c.AddPolicy("AllowCCORSOrigin", options => options
.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});

sencha touch - ajax call to server (url , extra parameter formation)

I am using this to get the result from server
controller.allVisitStore = new Ext.data.Store({
model: 'allVisit',
autoLoad : true,
proxy: {
type: 'ajax',
id: 'allvisit_app_localstore',
url: '/RadMobApp/api',
extraParams:{
action:'query',
queryName:'GET_ALL_VISIT',
authToken: localStorage.getItem("auth_token"),
patTicketId: localStorage.getItem("patientId"),
retFormat:'XML',
keyValuePair:'yes'
},
// the return will be XML, so lets set up a reader
reader: new Ext.data.XmlReader({
// records will have an "T4" tag
record: 'data'
})
}
});
but i am not getting any thing.But i formed this url in browser and checked this i got the correct result. now here i want to check is there any problem in the url formation.How to check the url formation with extra parameter which is pass through ajax. I have checked in Inspect element-> network -> api there is no any api request found there.Is anything wrong in my code. Thanks in advance...
Use Firebug for Firefox or Chrome's developer tools to see what's going on when that store attempts to load itself. My hunch is that your url is incorrect and should be url: '/api' because RadMobApp is probably your app root.

Resources