Breeze is not working with some project settings - asp.net-mvc

I have a problem using breeze on a project based on John Papa's HotTowel. I configured breeze like:
var mgr = new breeze.EntityManager('breeze/Breeze');
everything is ok but in the case I change the Project properties Start Action from Current Page to Specific Page: HotTowel/Index and breeze doesn't work properly.
I've checked the requests using firebug. It seems in this case application sends a GET request like this:
http://localhost:53180/HotTowel/Index/breeze/Breeze/Metadata
instead of
http://localhost:53180/breeze/Breeze/Metadata
I've also checked this part of breeze.js which is going to send get request.
The url parameter is set to breeze/Breeze/Metadata in both cases which seems correct.
ctor.prototype.fetchMetadata = function (metadataStore, dataService) {
var serviceName = dataService.serviceName;
var url = dataService.makeUrl("Metadata");
var deferred = Q.defer();
var that = this;
ajaxImpl.ajax({
url: url,
dataType: 'json',...
I've also tried ~/breeze/Breeze but it didn't work as remote service name.
As I'm new to web, probably it's not related to breeze.
The question is why the ajax call (or breeze) depends on how the project activates?

Add a / character to your configuration to execute the request relative to the base directory:
var mgr = new breeze.EntityManager('/breeze/Breeze');

The reason why this happens is because you specified a relative path for the EntityManager and if your url is localhost:53180/HotTowel/Index then the relative url for the EntityManager is localhost:53180/HotTowel/Index + /breeze/Breeze.
To correct the issue, change your EntityManager path to the following:
var mgr = new breeze.EntityManager('breeze/Breeze');

Related

Get requested URL in Startup.cs

I have multiple hostname binding on my IIS web site.
And I want to do some base setup during running Startup.cs, that should be dependent on what url has been called.
Lets say there is http://red.webapp.com and http://blue.webapp.com bindings to the same web site.
I tried to get url :
var request = HttpContext.Current.Request;
var url = request.Url.Scheme;
var auth = request.Url.Authority;
However as auth I have 127.0.0.1.
Is it possible to somehow get url that user tried to access?
Thank you.

Response Header issue on Azure Web Application

I am not sure what is happening here.
When I run my web application locally and click a button to download a file, the file is downloaded fine and Response header as you can see in the attached screenshot where it says local.
But when I publish the application to azure web app. Somehow the download button stops working. I checked the Response Header and you can see the difference.
What would cause this problem? The code is the same? Is there any settings that I should be setting in azure web app in azure portal?
Updated to add code
I have debugged remotely to figure out what is going on as #Amor suggested.
It is so strange that When I debug on my local machine first ExportTo action gets hit which prepares the TempData then Download action gets called once the first action completed with ajax call.
However, this is not the case when I debug remotely. Somehow the ExportTo action never gets called. It directly calls the Download action. As a result the TempData null checking is always null.
But why? Why on earth and how that is possible? Is there something cached somewhere?
I have wiped the content of web application on the remote and re-publish evertyhing to ensure everything is updated. But still no success.
here is the code:
[HttpPost]
public virtual ActionResult ExportTo(SearchVm searchVm)
{
var data = _companyService.GetCompanieBySearchTerm(searchVm).Take(150).ToList();
string handle = Guid.NewGuid().ToString();
TempData[handle] = data;
var fileName = $"C-{handle}.xlsx";
var locationUrl = Url.Action("Download", new { fileGuid = handle, fileName });
var downloadUrl = Url.Action("Download");
return Json(new { success = true, locationUrl, guid = handle, downloadUrl }, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult Download(string fileGuid, string fileName)
{
if (TempData[fileGuid] != null)
{
var fileNameSafe = $"C-{fileGuid}.xlsx";
var data = TempData[fileGuid] as List<Company>;
using (MemoryStream ms = new MemoryStream())
{
GridViewExtension.WriteXlsx(GetGridSettings(fileNameSafe), data, ms);
MVCxSpreadsheet mySpreadsheet = new MVCxSpreadsheet();
ms.Position = 0;
mySpreadsheet.Open("myDoc", DocumentFormat.Xlsx, () =>
{
return ms;
});
mySpreadsheet.Document.Worksheets.Insert(0);
var image = Server.MapPath("~/images/logo.png");
var worksheet = mySpreadsheet.Document.Worksheets[0];
worksheet.Name = "Logo";
worksheet.Pictures.AddPicture(image, worksheet.Cells[0, 0]);
byte[] result = mySpreadsheet.SaveCopy(DocumentFormat.Xlsx);
DocumentManager.CloseDocument("myDoc");
Response.Clear();
//Response.AppendHeader("Set-Cookie", "fileDownload=true; path=/");
Response.ContentType = "application/force-download";
Response.AddHeader("content-disposition", $"attachment; filename={fileNameSafe}");
Response.BinaryWrite(result);
Response.End();
}
}
return new EmptyResult();
}
here is the javascript:
var exportData = function (urlExport) {
console.log('Export to link in searchController: ' + urlExport);
ExportButton.SetEnabled(false);
var objData = new Object();
var filterData = companyFilterData(objData);
console.log(filterData);
$.post(urlExport, filterData)
.done(function (data) {
console.log(data.locationUrl);
window.location.href = data.locationUrl;
});
};
When Export button is clicked exportData function is called:
var exportToLink = '#Url.Action("ExportTo")';
console.log('Export to link in index: '+exportToLink);
SearchController.exportData(exportToLink);
As I mentioned that this code works perfectly on the local machine. something weird is happening on azure webapp that ExportTo action breakpoint is never gets hit.
I am not sure what else I could change to get the ExportTo action hit?
Based on the Response Header of Azure Web App, we find that the value of Content-Length is 0. It means that no data has been sent from web app server side.
In ASP.NET MVC, we can response file using following ways.
The first way, send the file which hosted on server. For this way, please check whether the excel file has been uploaded to Azure Web App. You could use Kudu or FTP to the folder to check whether the file is exist.
string fileLocation = Server.MapPath("~/Content/myfile.xlsx");
string contentType = System.Net.Mime.MediaTypeNames.Application.Octet;
string fileName = "file.xlsx";
return File(fileLocation, contentType, fileName);
The second way, we can read the file from any location(database, server or azure storage) and send the file content to client side. For this way, please check whether the file has been read successfully. You can remote debug your azure web app to check whether the file content hasn't been read in the right way.
byte[] fileContent = GetFileContent();
string contentType = System.Net.Mime.MediaTypeNames.Application.Octet;
string fileName = "file.xlsx";
return File(fileContent, contentType, fileName);
5/27/2017 Update
Somehow the ExportTo action never gets called. It directly calls the Download action. As a result the TempData null checking is always null.
How many instances does your Web App assigned? If your Web App have multi instances, the ExportTo request is handled by one instance and the Download request is handled by another instance. Since the TempData is store in memory of dedicated instance, it can't be got from another instance. According to the remote debug document. I find out the reason why the ExportTo action never gets called.
If you do have multiple web server instances, when you attach to the debugger you'll get a random instance, and you have no way to ensure that subsequent browser requests will go to that instance.
To solve this issue, I suggest you response the data directly from the ExportTo action or save the temp data in Azure blob storage which can't be accessed from multi instances.

MVC 5 bundling and Azure CDN (query string)

I have been following this tutorial: https://azure.microsoft.com/en-us/documentation/articles/cdn-serve-content-from-cdn-in-your-web-application/
Everything had been great until I noticed that bundled scripts and CSS files return with the cache: no-cache,expires: -1 and pragma: no-cache headers.
Of course, this has nothing to do with Azure. To prove this, I tested the bundles by accessing them directly from my site, instead of CDN - ie. mysite.com/bundles/mybundle?v={myassemblyversion}. The result was the same. When I disabled the CDN, and accessed the bundled file with the v query string generated by MVC, the headers were as expected: public caching, with the expiry time of one year.
I've tried to implement the IBundleTransform interface, but the context.BundleVirtualPath is read-only (even though it says gets or sets the virtual path...). I've also tried to modify the response headers at the Application_EndRequest(), but it didn't work, either. My last bet was writing IIS outbound rules, but since my bundles (used with "custom" v query string) don't return Last-Modified header, it was a futile attempt, too.
My question is: how can I use MVC bundling with Azure CDN if I want my bundled files to be cached on the client - that is, until the v query string changes?
I know I'm a little late to the game, but I did find a workaround. I'm making use of the code by Frison B Alexander here.
The issue is that once you rewrite the querystring for StyleBundles or ScriptBundles, the default caching behavior of one year resets to no-cache. This is solved by regenerating the exact same querystring per bundle that the MVC framework uses when specifying each Bundle's CDNPath.
Here's how it's done using the MVC Web App template. Here's the BundleConfig class:
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
//we have to go ahead and add our Bundles as if there is no CDN involved.
//this is because the bundle has to already exist in the BundleCollection
//in order to get the hash that the MVC framework will generate for the
//querystring.
Bundle jsBundle = new ScriptBundle("~/scripts/js3").Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/modernizr-*",
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js");
bundles.Add(jsBundle);
Bundle cssBundle = new StyleBundle("~/content/css3").Include(
"~/Content/bootstrap.css",
"~/Content/site.css");
bundles.Add(cssBundle);
#if Debug
bundles.UseCdn = false;
#else
bundles.UseCdn = true;
//grab our base CDN hostname from web.config...
string cdnHost = ConfigurationManager.AppSettings["CDNHostName"];
//get the hashes that the MVC framework will use per bundle for
//the querystring.
string jsHash = GetBundleHash(bundles, "~/scripts/js3");
string cssHash = GetBundleHash(bundles, "~/content/css3");
//set up our querystring per bundle for the CDN path.
jsBundle.CdnPath = cdnHost + "/scripts/js3?v=" + jsHash;
cssBundle.CdnPath = cdnHost + "/content/css3?v=" + cssHash;
#endif
}
//Frison B Alexander's code:
private static string GetBundleHash(BundleCollection bundles, string bundlePath)
{
//Need the context to generate response
var bundleContext = new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundlePath);
//Bundle class has the method we need to get a BundleResponse
Bundle bundle = BundleTable.Bundles.GetBundleFor(bundlePath);
var bundleResponse = bundle.GenerateBundleResponse(bundleContext);
//BundleResponse has the method we need to call, but its marked as
//internal and therefor is not available for public consumption.
//To bypass this, reflect on it and manually invoke the method
var bundleReflection = bundleResponse.GetType();
var method = bundleReflection.GetMethod("GetContentHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
//contentHash is whats appended to your url (url?###-###...)
var contentHash = method.Invoke(bundleResponse, null);
return contentHash.ToString();
}
}

HttpContext AbsolutePath goes to wrong URL for aliased pages - C#

On my website each page has links that are created in the codebehind, where the links are the current URL with one query parameter changed. To do this, I've been using this method (this specific example is for the pagination):
var queryValues = HttpUtility.ParseQueryString(HttpContext.Current.Request.QueryString.ToString());
queryValues.Set("page", num);
string url = HttpContext.Current.Request.Url.AbsolutePath;
string updatedQueryString = "?" + queryValues.ToString();
string newUrl = url + updatedQueryString;
return newUrl;
This worked on my local version fine. However, when I created each page in Ektron and added a manual alias, the URLs generated still went to the file location in the solution. For example, my original page was /WebAssets/Templates/EventListView.aspx. I created the page in Ektron as /Alumni/Events/List. I can go to /Alumni/Events/List, but then when I click on a page button the page that loads is /WebAssets/Templates/EventListView.aspx?page=2 instead of /Alumni/Events/List/?page=2
I found one solution:
var rawUrl = HttpContext.Current.Request.RawUrl;
var url = rawUrl.Split('?')[0];
string newUrl = url + updatedQueryString;
Use the QuickLink property of the primary contentblock for /Alumni/Events/List, this will be the alias use want to use for your page links or for redirects to the same page. This is probably ContentData.QuickLink if you're already loading the ContentData at some point in the code.
Notes:
Aliasing may remove your "page" querystring parameter by default, to resolve this issue, edit your alias in the Workarea to have a "Query String Action" of "Append".
Make sure you preprend a "/" to the QuickLink value (if it's not absolute and not prepended already) if using it on the frontend, otherwise your links will bring you to something like /Alumni/Events/List/Alumni/Events/List?page=2, which is no good.

Using GitLab API to set external issues tracker settings?

I'm using GitLab with an external issue tracker (JIRA), and it works well.
My problem is when I create a new GitLab project (using API), I have to go the GitLab's project settings and manually select the issue tracker I want to use and manually enter the project's id of my external issue tracker.
This screen will be more eloquent:
(source: bayimg.com)
(The two fields I am talking about are "Issue tracker" and "Project name or id in issues tracker")
So here is my question: is there any way to set up this two fields automatically, using API or other ? Currently, GitLab API does not mention anything about external issues tracker settings.
This code helped me to automatically set the GitLab's external issues-tracker settings, using Apache HttpClient and Jsoup.
This code is absolutely not 100% good, but it shows the main idea, wich is to recreate the corresponding POST request that the web form sends.
// 1 - Prepare the HttpClient object :
BasicCookieStore cookieStore = new BasicCookieStore();
LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCookieStore(cookieStore)
.setRedirectStrategy(redirectStrategy)
.build();
try {
// 2 - Second you need to get the "CSRF Token", from a <meta> tag in the edit page :
HttpUriRequest getCsrfToken = RequestBuilder.get()
.setUri(new URI("http://localhost/_NAMESPACE_/_PROJECT_NAME_/edit"))
.build();
CloseableHttpResponse responseCsrf = httpclient.execute(getCsrfToken);
try {
HttpEntity entity = responseCsrf.getEntity();
Document doc = Jsoup.parse(EntityUtils.toString(entity));
String csrf_token = doc.getElementsByAttributeValue("name", "csrf-token").get(0).attr("content");
// 3 - Fill and submit the "edit" form with new values :
HttpUriRequest updateIssueTracker = RequestBuilder
.post()
.setUri(new URI("http://localhost/_NAMESPACE_/_PROJECT_NAME_"))
.addParameter("authenticity_token", csrf_token)
.addParameter("private_token", "_MY_PRIVATE_TOKEN_")
.addParameter("_method", "patch")
.addParameter("commit", "Save changes")
.addParameter("utf8", "✓")
.addParameter("project[issues_tracker]", "jira")
.addParameter("project[issues_tracker_id]", "_MY_JIRA_PROJECT_NAME_")
.addParameter("project[name]", "...")
...
.build();
CloseableHttpResponse responseSubmit = httpclient.execute(updateIssueTracker, httpContext);
} finally {
responseCsrf.close();
}
} finally {
httpclient.close();
}
Change _NAMESPACE_/_PROJECT_NAME_ to make it corresponds to your project URL, change _MY_PRIVATE_TOKEN_ with your admin account's token, and change _MY_JIRA_PROJECT_NAME_ with ... your jira project's name.

Resources