Calling C# code from JavaScript in SharePoint - javascript

Ok here's what I'm trying to do.
I have this custom action (button on my SharePoint-ribbon). This should call a Javascript, which in turn should call a C#-code.
I have the following:
<CustomAction
Id="Ribbon.Documents.DocsetZip"
Title="Download Document Set as ZIP"
RegistrationType="ContentType"
RegistrationId="0x0120D520"
Location="CommandUI.Ribbon"
>
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.Documents.Share.Controls._children">
<Button Id="Ribbon.Document.Share.DownasZip"
Sequence="20"
Command="Ribbon.ManageDocumentSet.MDS.Manage.DownZip"
Alt="Download as ZIP"
Image16by16="/_layouts/images/zipfile16x.png"
Image32by32="/_layouts/images/zipfile32x.png"
LabelText="Download as ZIP file"
ToolTipTitle="Download as ZIP file"
ToolTipDescription="Compress the document set and download"
TemplateAlias="o1"/>
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler
Command="Ribbon.ManageDocumentSet.MDS.Manage.DownZip"
CommandAction="javascript:__doPostBack('DownloadZipDelegateEvent', '')" />
</CommandUIHandlers>
</CommandUIExtension>
And i have a class:
public class MyRibbonDelegateClass : WebControl
{
protected override void OnLoad(EventArgs e)
{
this.EnsureChildControls();
base.OnLoad(e);
if (this.Page.Request["__EVENTTARGET"] == "DownloadZipDelegateEvent")
{
using (TextWriter writer = File.CreateText("C:\\temp\\perl.txt"))
{
//
// Write one line.
//
writer.WriteLine("First line");
//
// Write two strings.
//
writer.Write("A ");
writer.Write("B ");
//
// Write the default newline.
//
writer.Write(writer.NewLine);
}
}
}
It seems my code gets executed, but I cannot find my file anywhere.
What am I missing?

you can use __DoPostback to invoke a server side hit from javascript.
<script type="text/javascript">
function ServerPostWithParameter(parameter)
{
__doPostBack('btnSave', parameter)
}
</script>
in server side,
public void Page_Load(object sender, EventArgs e)
{
string parameter = Request["__EVENTARGUMENT"]; // this is your parameters
// Request["__EVENTTARGET"]; // this is your button
}

You can just create an HttpHandler with your server-side code and call it with parameters from JavaScript.
E.g. create an ~sitecollection/_layouts/15/MyCustomHandler.ashx and call it from JavaScript like this (SharePoint 2013 uses virtual path to layouts directory as '_layouts/15', SharePoint 2010 -- just '_layouts'):
$.get(_spPageContextInfo.siteServerRelativeUrl + '/_layouts/15/MyCustomHandler.ashx?Param1=Value1&Param2=Value2');

I've solved it as follows :
function getOutlook() {
var xmlHttpReq = createXMLHttpRequest();
xmlHttpReq.open("GET", _spPageContextInfo.siteServerRelativeUrl + "/_layouts/SendDocuments/MyCustomHandler.ashx?ItemsArray=" + fileRefArray, false);
xmlHttpReq.send(null);
}
function createXMLHttpRequest() {
try { return new XMLHttpRequest(); } catch (e) { }
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { }
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { }
alert("XMLHttpRequest not supported");
return null;
}

Related

Xamarin iOS HybridWebView does not execute JavaScript files for iOS 15> iPads

I am developing a cross platform app that has a HybridWebView and displays a local html file. I have a wwwroot folder that contains the html file, css files, js files and all other resources. I have built the complete folder as BundleResource. I also start a local web server with EmbedIO. When I launch the app on iPads(iOS 15>), it does not execute the JavaScript files. On iPhones(iOS 15>) the app works fine. Also on iPads with iOS 12 the app works. Also, the app works on Safari no matter what device is used.
I have already added in info.plist NSAppTransportSecurity with NSAllowsArbitraryLoads = true.Also, I have developed a Swift app with a WebView and tried to use the local web server of the Xamarin.iOS app to present the app there. But again JavaScript is not executed (I also set the preferences regarding JavaScript).
My problem:
I don't understand why the application works on Safari, iPhones and old iPads, but not on new iPads. I suspect that you have to enable JavaScript, but can't find a corresponding solution.
To mention:
I load only one js file in the index.html. This js file in turn loads other js files (This works on all devices except the new iPads, as mentioned above).
Below I have added the HybridWebView.cs, the HybridWebViewRenderer.cs, the MainPage.xaml.cs and MainPage.xaml.
MainPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:extensions="clr-namespace:Viewer.Extensions;assembly=Viewer"
x:Class="Viewer.MainPage">
<StackLayout>
<extensions:HybridWebView x:Name="HybridWebView" Uri="{Binding WebViewSource}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
MainPage.xaml.cs:
namespace Viewer
{
[DesignTimeVisible(false)]
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
private readonly LocalWebServer _server = new LocalWebServer();
private string _webViewSource;
public string WebViewSource
{
get => _webViewSource;
set
{
_webViewSource = value;
OnPropertyChanged(nameof(WebViewSource));
}
}
public MainPage()
{
InitializeComponent();
BindingContext = this;
NavigationPage.SetHasNavigationBar(this, false);
HybridWebView.RegisterAction(data =>
{
DisplayAlert("Alert", "Hello " + data, "OK");
});
HybridWebView.RegisterQRAction(() =>
{
try
{
ZXingScannerPage scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) =>
{
scanPage.IsScanning = false;
Device.BeginInvokeOnMainThread(async () =>
{
await Navigation.PopAsync();
var barcode = result.Text.ParseBarcode();
switch (barcode.BarcodeType)
{
case BarcodeType.Hotspot:
{
await HybridWebView.EvaluateJavaScriptAsync(
$"javascript:doLoadHS('{barcode.Datamodule}.html', '{barcode.Hotspot.figureId}', '{barcode.Hotspot.hotspotId}');");
break;
}
case BarcodeType.Datamodule:
default:
{
await HybridWebView.EvaluateJavaScriptAsync(
$"javascript:doLoad('{barcode.Datamodule}.html');");
break;
}
}
});
};
Device.BeginInvokeOnMainThread(() =>
{
Navigation.PushAsync(scanPage);
});
}
catch (Exception ex)
{
DisplayAlert("QR", $"Error while reading qr code: {ex.Message}", "OK");
}
});
HybridWebView.RegisterProjectSelectionAction(() =>
{
_server.Dispose();
Navigation.PopToRootAsync();
});
var docpath = Helper.PathAddBackslash(Path.Combine(DependencyService.Get<IApplicationConfigurationService>().DocumentationRootPath, Init.NAME_DIR_WWWROOT));
_server.StartWebServer(docpath, false, false);
WebViewSource = $"{LocalWebServer.Url}/index.html";
NavigationPage.SetHasBackButton(this, false);
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
}
HybridWebView.cs:
using System;
using Xamarin.Forms;
namespace Viewer.Extensions
{
public class HybridWebView : WebView
{
Action<string> action;
Action qrAction;
Action projectSelectionAction;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void RegisterQRAction(Action callback)
{
qrAction = callback;
}
public void RegisterProjectSelectionAction(Action callback)
{
projectSelectionAction = callback;
}
public void Cleanup()
{
action = null;
qrAction = null;
projectSelectionAction = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
public void InvokeQRAction()
{
qrAction?.Invoke();
}
public void InvokeProjectSelectionAction()
{
projectSelectionAction?.Invoke();
}
}
}
HybridWebViewRenderer.cs:
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace Viewer.iOS.Views
{
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}" +
"function invokeCSharpQRAction(data){window.webkit.messageHandlers.invokeQRAction.postMessage(data);}";
WKUserContentController userController;
public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
{
}
public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
userController = config.UserContentController;
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(this, "invokeAction");
userController.AddScriptMessageHandler(this, "invokeQRAction");
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
userController.RemoveScriptMessageHandler("invokeQRAction");
HybridWebView hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
LoadRequest(new NSUrlRequest(new NSUrl(((HybridWebView)Element).Uri)));
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var eventArgs = message.Body.ToString().ParseEventArgs();
switch (eventArgs.name)
{
case "invokeAction":
((HybridWebView)Element).InvokeAction(eventArgs.payload);
break;
case "invokeQRAction":
((HybridWebView)Element).InvokeQRAction();
break;
}
}
}
}
The problem here is probably with your Javascript.
Mobile and older devices often suppress the console errors of Javascript and instead of an error page or an exception, further Javascript is not executed and it seems as if it is not executed at all.
Especially with complex Javascript with many usings and references it is enough if there is a problem with one reference, so you don't see anything.
Here it can help to simplify the Javascript and to rebuild it bit by bit to localize the error.

MVC SignalR keep increasing request count on each reload

I'm creating an ASP.NET MVC application which uses "SqlDependecy" and "SignalR" technologies to maintain real-time communication with the server based on database changes. It simply inspect a field value changes in specific database record and then display it on the browser.
The attempt works perfectly fine. But when I monitor the network requests through the browsers "Network" performance, the request count increases by 1 in every refresh of the page.
As in the image.
Initial page load only make one request.
First refresh after the initial load and then db change will lead to make 2 requests.
Second refresh after the initial load and then db change will lead to make 3 requests.
so on...
The js code I tried is given below.
It seams as an problem to me. If this is a real problem, Any advice on this will be highly appreciated. Thank you very much.
<script type="text/javascript">
$(function () {
var jHub = $.connection.journeyHub;
$.connection.hub.start();
jHub.client.ListenChange = function () {
getData();
}
jHub.client.ListenChange();
});
function getData() {
$.ajax({
url: 'GetValue',
type: 'GET',
dataType: 'json',
success: function (data) {
if (data == "pending") {
$("#box").css({ "background-color": "orange" });
}
else if (data == "deny") {
$("#box").css({ "background-color": "red" });
}
else if (data == "success") {
$("#box").css({ "background-color": "green" });
}
}
});
}
</script>
<div id="box" style="width:100px; height:100px; background-color: gray;"></div>
[Edit v1]
Here is my Controller where the event handler is located.
public class TravelController : Controller
{
SqlConnection link = new SqlConnection(ConfigurationManager.ConnectionStrings["linkTraveller"].ConnectionString);
// GET: Travel
public ActionResult Listen()
{
return View();
}
public ActionResult GetValue()
{
using (IDbConnection conn = link)
{
string query = #"SELECT [Status] FROM [dbo].[Journey] WHERE [Id]=1";
SqlCommand command = new SqlCommand(query, link);
SqlDependency sqlDep = new SqlDependency(command);
sqlDep.OnChange += new OnChangeEventHandler((sender, e) => sqlDep_OnChange(sender, e));
conn.Open();
string status = command.ExecuteScalar().ToString();
return Json(status, JsonRequestBehavior.AllowGet);
}
}
private void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
JourneyHub.Start();
}
}
Here is the Hub
public class JourneyHub : Hub
{
public static void Start()
{
var context = GlobalHost.ConnectionManager.GetHubContext<JourneyHub>();
context.Clients.All.ListenChange();
}
}
Off the top of my head, I would say you are not decrementing your trigger handlers, sql dependency triggers only fire once and then they are gone, you have to remember the remove the event handler for it or they just keep adding but, but I will know for sure if you can post your sql dependency trigger code.
Here is a sample from something I did many years ago, but the idea is still the same.
try
{
using (
var connection =
new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT [Id]
,[FName]
,[LName]
,[DOB]
,[Notes]
,[PendingReview]
FROM [dbo].[Users]",
connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
command.ExecuteReader();
}
}
}
catch (Exception e)
{
throw;
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
if (dependency != null) dependency.OnChange -= dependency_OnChange;
//Recall your SQLDependency setup method here.
SetupDependency();
JobHub.Show();
}

retrieve value from javascript function in codebehind

How can I retrieve value from javascript function in codebehind, on page load ..
javascript function like :
<script type="text/javascript">
function isIFrame() {
var isInIFrame = (top.location != self.location);
if (isInIFrame) {
return "inside";
}
else {
return "outside";
}
}
</script>
and code behind like :
protected void Page_Load(object sender, EventArgs e)
{
string resutOfExecuteJavaScript = "";
// resutOfExecuteJavaScript = isIFrame(); // from javascript
if (resutOfExecuteJavaScript == "inside")
{
// do something
}
else
{
// do something
}
}
thank you.
You cannot directly call a client side javascript method from server side code . For that first you need to assign the function result to value of some hidden variable and then access it in server side
Suppose you have an hidden field like this
<input type="hidden" runat="server" id="hdnVal"/>
then you can set the value as below
document.getElementById("hdnVal").value=isIFrame();
then at serve side
string resutOfExecuteJavaScript = hdnVal.Value;
using _doPostBack, you can solve this one
<script type="text/javascript">
function isIFrame() {
var isInIFrame =(top.location != self.location);
var result;
if (isInIFrame) {
result="inside";
}
else
{
result ="outside";
}
__doPostBack('callPostBack', result);
</script>
</head>
In code behind section
protected void Page_Load(object sender, EventArgs e)
{
this.ClientScript.GetPostBackEventReference(this, "arg");
if (IsPostBack)
{
string eventTarget = this.Request["__EVENTTARGET"];
string eventArgument = this.Request["__EVENTARGUMENT"];
if (eventTarget != String.Empty && eventTarget == "callPostBack")
{
if (eventArgument == "inside"){
//do something
}
else if(eventArgument == "outside")
{
//do something
}
}
else
{
// set the button click
btnclick.Attributes.Add("onClick", "isIFrame();");
}
}
Below link will help you out to get more idea.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=203
in javascript file or your script add :
function SetHiddenVariable()
{
document.getElementById(inpHide).value= "value";
}
in .aspx add this tag:
<input id="inpHide" type="hidden" runat="server" />
in aspx.cs (c# file) add :
anyVariable = inpHide.Value;

How to register client script in HttpHandler to execute javascript function?

I have an html page that using ajax to call HttpHandler which needs to return javascript function back to client, so, when button is clicked this function gets executed.
I'm learning ajax now and using old fashion way to call it.
Here is my .html file:
<script language="javascript">
var XMLHttpRequestObject = false;
try {
XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP");
} catch (exception1) {
try {
XMLHttpRequestObject = new ActiveXObject("Microsoft.MLHTTP");
}
catch (exception2) {
XMLHttpRequestObject = false;
}
}
if (!XMLHttpRequestObject && window.XMLHttpRequest) {
XMLHttpRequestObject = new XMLHttpRequest();
}
function getData(dataSource) {
if (XMLHttpRequestObject) {
XMLHttpRequestObject.open("GET", dataSource);
XMLHttpRequestObject.onreadystatechange = function () {
if (XMLHttpRequestObject.readyState == 4
&& XMLHttpRequestObject.status == 200) {
eval(XMLHttpRequestObject.responseText);
}
}
XMLHttpRequestObject.send(null);
}
}
function alerter() {
var targetDiv = document.getElementById("targetDiv");
targetDiv.innerHTML = "Got the JavaScript OK.";
}
</script>
</head>
<body>
<h1>Returning JavaScript</h1>
<form>
<input type="button" value="Fetch JavaScript" onclick="getData('http://myserver/DataSources/data.ashx')" />
</form>
<div id="targetDiv">
<p>The fetched data will go here.</p>
</div>
</body>
Than I have my HttpHandler where I need to register client script to call the function:
public class data1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
EchoMessage(context);
}
private void EchoMessage(HttpContext context)
{
}
}
What should I write in my EchoMessage to register the script needed to run on a client side?
Thank you
You can use RegisterStartupScript or RegisterClientScriptBlock to declare a script on the server and pass it on to be executed on the client. These are static functions of ClientScript and ScriptManager.
Differences between ScriptManager and ClientScript when used to execute JS?
Difference between RegisterStartupScript and RegisterClientScriptBlock?
After all, I just decided to go with context.Response.Write("alerter()") and it seems to be working. Not sure if this is the right solution though
You can simply use the ScriptManager.RegisterStartupScript, which worked for me as below:
Page page = HttpContext.Current.Handler as Page;
ScriptManager.RegisterStartupScript(page, this.GetType(), "ErrorSave", "$cmsj('.alert-label').html('Maximum 4 quick links are allowed.');", true);

When I use window.location.href ,then my another function not calling .Following is my javascript code

I am using Following code..
When I click on the link, the javascript Hello() function is invoked
I want to use window.location.href
But when I use this the following __doPostBack('Button2_Click'), it does not work.
But when remove window.location.href from the following code then __doPostBack('Button2_Click') does work.
<script type="text/javascript">
function Hello(clicked_id) {
var abc = "http://localhost:2621/OrgChart.aspx?id" + clicked_id;
window.location.href = abc;
__doPostBack('Button2_Click');
return false;
}
</script>
<a id="A1" href="javascript:Hello();">LINK</a>
This is my code behind code...
public partial class WebForm17 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ClientScript.GetPostBackEventReference(this, string.Empty);//This is important to make the "__doPostBack()" method, works properly
if (Request.Form["__EVENTTARGET"] == "Button2_Click")
{
//call the method
Button2_Click(this, new EventArgs());
}
}
protected void Button2_Click(object sender, EventArgs e)
{
Label1.Text = "Method called!!!";
EmpInfo emp = new EmpInfo();
DA_EmpInfo da_emp = new DA_EmpInfo();
List<EmpInfo> lei = da_emp.GetAllEmployeeInfoByEmpId("MJ-IB-1");
DetailsView1.DataSource = lei;
DetailsView1.DataBind();
}
}
I guess, __doPostBack is making a request to the server and you break it by using window.location.href = abc;.
You should use some callback from this request to redirect to your url.
try to use setTimeOut function
setTimeout(function () {
window.location.href = abc;
}, 1000);
this will wait 1 second for finish of __doPostBack() function.
Or if you don't want to use timeOut, paste window.location.href = abc; line to end of the __doPostBack() function.

Categories

Resources