WCF SSE via SignalR - wcf

I have a few different WCF Services running. I would like to send one-way messages to clients who will be running IE 11. I would like to send the messages in the form of a class (ServiceName,Message,MessageDT), and then any clients listening to a particular Service would receive the message, and display it to user. I have viewed a few tutorials on SignalR and they all seem to be slightly different scenarios, like a chat application. Even the Stock Ticker example, has this random class that works on a timer to update stock prices. Its confusing. Does anybody have a good sample tutorial on how to do what I want to do?

Finally I was able to figure this out, and so I thought I would post the answer for those who are need.
First I created a class library (WMAppLib) with my message class:
Public Class VirtualConsoleMessage
Private m_AppName As String
Public Property AppName() As String
Get
Return m_AppName
End Get
Set(value As String)
m_AppName = value
End Set
End Property
Private m_MessageDT As DateTime
Public Property MessageDT() As DateTime
Get
Return m_MessageDT
End Get
Set(value As DateTime)
m_MessageDT = value
End Set
End Property
Private m_Message As String
Public Property Message() As String
Get
Return m_Message
End Get
Set(value As String)
m_Message = value
End Set
End Property
End Class
Then in my Web Application, I added SignalR references, and also a reference to my class library. I then created a Hub:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System.Threading.Tasks;
using WMAppLib;
namespace WMApp_WebAdmin
{
[HubName("VirtualConsoleMessageHub")]
public class Virtual_ConsoleHub : Hub
{
public void AddSubscription(string AppName)
{
Groups.Add(Context.ConnectionId,AppName);
}
public void BroadcastMessage(VirtualConsoleMessage vcm)
{
string strClientMessage = vcm.MessageDT.ToString("MM/dd/yyyy hh:mm:ss tt") + " : " + vcm.Message;
Clients.Group(vcm.AppName).newMessageReceived(strClientMessage);
}
}
}
My web page (VirtualConsole) has the following markup:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="VirtualConsole.aspx.cs" Inherits="WMApp_WebAdmin.VirtualConsole" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Virtual Console</title>
<link href="/CSS/styleVC.css" type="text/css" rel="stylesheet" />
<script src="/JS/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
<script src="signalr/hubs"></script>
<script src="/JS/VirtualConsole.js" type="text/javascript""></script>
</head>
<body>
<form id="form1" runat="server">
<div id="divConsole" runat="server">
</div>
<asp:HiddenField ID="AppName" runat="server" />
<asp:HiddenField ID="Endpoint" runat="server" />
<asp:HiddenField ID="AssemblyName" runat="server" />
<asp:HiddenField ID="ClassName" runat="server" />
</form>
</body>
</html>
My VirtualConsole.js has the following:
$(function () {
var myVirtualConsoleHub = $.connection.VirtualConsoleMessageHub;
myVirtualConsoleHub.client.newMessageReceived = function (message) {
$("#divConsole").append("<p>" + message + "</p>");
}
$.connection.hub.url = "/signalr";
$.connection.hub.start().done(function () {
myVirtualConsoleHub.server.addSubscription($("#AppName").val());
}).fail(function (error) {
$("#divConsole").append("<p>" + error + "</p>");
});;
});
$().ready(function () {
var endpoint = $("#Endpoint").val();
});
In my WCF Service I added the SignalR, and the SignalR.Client. I also added a reference to my WMAppLib class library. In my main code I added two global variables:
Dim virtualConsoleHubConnection As HubConnection
Dim virtualConsoleHubProxy As IHubProxy
In My Public Sub New() I set these to values in my App.config:
virtualConsoleHubConnection = New HubConnection(ConfigurationManager.AppSettings("virtualConsoleHubURL"))
virtualConsoleHubProxy = virtualConsoleHubConnection.CreateHubProxy(ConfigurationManager.AppSettings("virtualConsoleHubName"))
These are set in the App.Config as:
<add key="virtualConsoleHubURL" value="http://localhost:49716/signalr/hubs"/>
<add key="virtualConsoleHubName" value="VirtualConsoleMessageHub"/>
Then I added one Private Sub to handle the broadcasting of all messages to the SignalR hub:
Private Sub WriteToVirtualConsole(ByVal vcm As VirtualConsoleMessage)
Try
virtualConsoleHubConnection.Start()
virtualConsoleHubProxy.Invoke("BroadcastMessage", vcm)
Catch ex As Exception
Finally
If virtualConsoleHubConnection.State = Microsoft.AspNet.SignalR.Client.ConnectionState.Connected Then
virtualConsoleHubConnection.Stop()
End If
End Try
End Sub
Then anytime I do a Console.WriteLine I just call this sub:
WriteToVirtualConsole(New VirtualConsoleMessage With {.AppName = "MyWCFService", .MessageDT = Now, .Message = "I just did something"})
It then gets displayed on my WebPage Virtual Console page.

Related

Pdf Document Link control error - PdfDocumentLink.ascx

I just upgraded from 5.1 to 7.0 and now I am getting this error on one of the pages that have a PdfDocumentLink control (in Edit Mode):
A required control was not found in the template for "~/Sitefinity/Extensions/WidgetTemplates/Libraries/Documents/PdfDocumentLink.ascx". The control must be assignable from type "System.Web.UI.HtmlControls.HtmlGenericControl" and must have ID "itemsContainer".
I get a 500 in Preview mode.
This is the code for the ascx, in \Sitefinity\Extensions\WidgetTemplates\Libraries\Documents
<%# Control Language="C#" %>
<%# Register TagPrefix="sitefinity" Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" %>
<%# Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
<sitefinity:ResourceLinks id="resourcesLinks2" runat="server" UseEmbeddedThemes="false" Theme="Default">
<sitefinity:ResourceFile Name="~/Sitefinity/Extensions/WidgetTemplates/Libraries/Documents/PdfDocumentLink.css" Static="true" />
</sitefinity:ResourceLinks>
<sitefinity:SitefinityHyperLink ID="documentLink" runat="server" target="_blank" CssClass="PdfDocumentLink" />
<sf:BrowseAndEditToolbar ID="browseAndEditToolbar" runat="server" Mode="Edit"></sf:BrowseAndEditToolbar>
Here's the cs file ... under C:\inetpub\xxx\App_Code\Widgets
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace xxx.Sitefinity.Widgets.Libraries.Documents {
/// <summary>
/// Summary description for PdfDocumentLink
/// </summary>
public class PdfDocumentLink : Telerik.Sitefinity.Modules.Libraries.Web.UI.Documents.DocumentLink {
public PdfDocumentLink() : base () {
//
// TODO: Add constructor logic here
//
}
public override string LayoutTemplatePath {
get {
return "~/Sitefinity/Extensions/WidgetTemplates/Libraries/Documents/PdfDocumentLink.ascx";
}
set {
base.LayoutTemplatePath = value;
}
}
public string LinkTitle {
get;
set;
}
protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
if (this.LinkTitle != null)
this.DocumentLinkControl.Text = this.LinkTitle;
}
}
}
And ToolboxesConfig.config file:
...
<toolboxesConfig xmlns:config="urn:telerik:sitefinity:configuration" xmlns:type="urn:telerik:sitefinity:configuration:type" config:version="7.0.5100.0">
<toolboxes>
<toolbox name="PageControls">
<sections>
<add name="ContentToolboxSection">
<tools>...
<add enabled="True" type="OneCommand.Sitefinity.Widgets.Libraries.Documents.PdfDocumentLink" title="PDF Document Link" description="Link to a PDF Document" cssClass="sfDownloadLinkIcn" moduleName="Libraries" Name="PDFDocumentLink" visibilityMode="None" name="PDFDocumentLink" />
If I delete the widget, and add it back in, and select a pdf document, I get the same error.
The Document Link widget appears to work ok, but that one doesn't have the left side PDF icon that we want to display.
Any ideas?
Try adding this to your .ascx file:
<div runat="server" id="itemsContainer"></div>

far future Expires header for static contents

how wrote here http://developer.yahoo.com/performance/rules.html
For static components: implement "Never expire" policy by setting far future Expires header
i can gain performace avoiding http requests with a response as "304".
In official play! documentation i can see how set cache-controll directives, but how i can set far future Expires header?
best regards Nicola
edit: thanks for the replay now it work as well! here there are the classes:
conf/routes
# Static files
GET /assets/stylesheets/img/:name controllers.StaticFilesController.getBoostrapImg(name)
GET /assets/images/*name controllers.StaticFilesController.getImg(name)
GET /assets/stylesheets/*name controllers.StaticFilesController.getCss(name)
GET /assets/javascripts/*name controllers.StaticFilesController.getJs(name)
controllers/StaticFilesController.java
package controllers;
import org.apache.http.impl.cookie.DateUtils;
import java.util.*;
import play.mvc.*;
import services.FileName;
import play.*;
public class StaticFilesController extends Controller {
private static String nextYearString = StaticFilesController
.getNextYearAsString();
public static Result getImg(String path) {
FileName fileName = new FileName(path);
response().setHeader(EXPIRES, nextYearString);
response().setContentType("image/" + fileName.extension());
return ok(Play.application().getFile("/public/images/" + path));
}
public static Result getBoostrapImg(String path) {
FileName fileName = new FileName(path);
response().setHeader(EXPIRES, nextYearString);
response().setContentType("image/" + fileName.extension());
return ok(Play.application().getFile(
"/public/images/" + fileName.filename() + "."
+ fileName.extension()));
}
public static Result getCss(String path) {
response().setHeader(EXPIRES, nextYearString);
response().setContentType("text/css");
return ok(Play.application().getFile("/public/stylesheets/" + path));
}
public static Result getJs(String path) {
response().setHeader(EXPIRES, nextYearString);
response().setContentType("application/x-javascript");
return ok(Play.application().getFile("/public/javascripts/" + path));
}
private static String getNextYearAsString() {
Calendar calendar = new GregorianCalendar();
calendar.add(Calendar.YEAR, 1);
return DateUtils.formatDate(calendar.getTime());
}
}
services/FileName.java
package services;
/**
* This class assumes that the string used to initialize fullPath has a
* directory path, filename, and extension. The methods won't work if it
* doesn't.
*/
public class FileName {
private String fullPath;
private char pathSeparator, extensionSeparator;
public FileName(String str, char sep, char ext) {
fullPath = str;
pathSeparator = sep;
extensionSeparator = ext;
}
public FileName(String str)
{
fullPath = str;
pathSeparator = '/';
extensionSeparator = '.';
}
public String extension() {
int dot = fullPath.lastIndexOf(extensionSeparator);
return fullPath.substring(dot + 1);
}
public String filename() { // gets filename without extension
int dot = fullPath.lastIndexOf(extensionSeparator);
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(sep + 1, dot);
}
public String path() {
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(0, sep);
}
}
And the views/main.scala.html
#(skin: String)(content: Html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>LibreTitan</title>
<link rel="stylesheet" media="screen" href="#routes.StaticFilesController.getCss("bootstrap/bootstrap.min.css")">
#if(skin != null && !skin.equals("")) {
<link rel="stylesheet" media="screen" href="#routes.StaticFilesController.getCss(skin+".min.css")">
}
<link rel="shortcut icon" type="image/png" href="#routes.StaticFilesController.getImg("favicon.png")">
<script async src="#routes.StaticFilesController.getJs("jquery-1.9.0.min.js")"></script>
<script async src="#routes.StaticFilesController.getJs("bootstrap.min.js")"></script>
</head>
<body>
<div class="container">
#content
</div>
</body>
</html>
Never expire policy in this context means that should add Expire header to your response which date is in far future, for an example 10 years since now. You can easily do that in Play as described in the Manipulating the response doc. example:
public static Result index() {
response().setHeader(EXPIRES, "Thu, 16 Feb 2023 20:00:00 GMT");
return ok("<h1>Hello World!</h1>");
}
Of course instead giving expire date as a String you should use some method to calculate it dynamicaly, you can do that with org.joda.time.DateTime (available in Play) and its methods like: plusYears(int years). Most important is that should be formatted finally in RFC 1123 date format.
Edit, of course you can return different kinds of Results - also binary as described in the doc ('Results' section), to check all available options look into API of: play.mvc.Results it can be: ok(Content content) - typical when you render some view, ok(java.io.File content), ok(java.io.InputStream content), etc.
On the other hand...
I'd definitely recommend to DO NOT use Play for serving far future static contents (and any other static, public contents as well). Although you can do it easily, as described above, IMHO it's redundant waste of Play's resources as you need to handle all requests for any single image, script, style... whatever.
Consider using common... HTTP server for that job (nginx, lighthttpd, Apache) or even better some distributed CDN. In that case your app can concern on executing its logic instead of searching the stylesheets on the disk.
P.S. Remember that if you are using Play instead of HTTP server, for adding new static contents which are served from the /public folder you'll need to restart the application, so at least make sure that you are keeping them in some dedicated folder apart of application, so you can add/remove/replace them without stopping the application.

How to deploy ActiveX dll from web page

Been trying off and on for days now and can't figure this out. I have written a C# class file for an Intranet app to control the local serial ports. It works great when I manually register the dll using regasm, however, I need to deploy this control from a web page without having to manually register it. I tried creating a Setup Project in Visual Studio 2010, it compiled fine yet I can not open the object in a webpage.
Here are the pertinent lines of code from my C# class:
namespace wmsSerialPorts
{
[Guid("55D31498-12A5-4FF0-942D-3B0BA449CA7B")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface iAxDevices
{
[DispId(1)]
int OpenPort(string sComPort);
[DispId(2)]
int ClosePort();
[DispId(3)]
int SendCmd(string sCmd);
[DispId(4)]
string GetLastError();
//[DispId(5)]
//string ReadLine();
[DispId(6)]
string ReadWeight();
[DispId(7)]
Microsoft.JScript.ArrayObject GetJsPorts();
[DispId(8)]
void prtLabel(string sItemNum, string sQty, string sDesc, string sWoNum, string sBoxID, string sBoxIDBarCode, string sBoxIDorig);
[DispId(9)]
void prtLabelQC(string sItemNum, string sQty, string sDesc, string sWoNum, string sBoxID, string sBoxIDBarCode, string sBoxIDorig, string sNeedDate, string sRecOverride);
[DispId(10)]
void prtReset();
}
[Guid("E59C5B7E-EF1F-4241-A9FD-191EF8FCC167")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[ProgId("AxDevices")]
public class AXDevices : wmsSerialPorts.SerialCom, iAxDevices, wmsSerialPorts.IObjectSafety
As I mentioned, if I use regasm wmsSerialPorts.dll, the object works great when called from JavaScript like this:
myAx = new ActiveXObject("AXDevices");
My Setup project contains a wmsSerialPorts.inf file:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Setup Hooks]
install=install
[install]
run=msiexec.exe /package """%EXTRACT_DIR%\ActiveXSetup.msi""" /qn
.... and an ActiveXBuild.ddf file:
.Set DiskDirectoryTemplate=cab
.Set CabinetNameTemplate=ActiveXSetup.cab
Debug\ActiveXSetup.msi
wmsSerialPorts.inf
My wmsSerialPorts.dll file is properly referenced as a detached asseembly and building the Setup Project created the ActiveXSetup.cab and ActiveXSetup.msi files as expected.
I then created this HTML page to load the object:
<!DOCTYPE>
<html>
<head>
<title>Test</title>
</head>
<body>
<!-- <object id="AXDevices" classid="clsid:E59C5B7E-EF1F-4241-A9FD-191EF8FCC167" codebase="https://10.0.2.53/BIDWMS/ActiveXSetup.cab">
</object>-->
<object id="AXDevices" classid="clsid:E59C5B7E-EF1F-4241-A9FD-191EF8FCC167" codebase="ActiveXSetup.cab">
</object>
<script type="text/javascript">
try {
var obj = document.AXDevices;
if (obj) {
alert(obj.SayHello());
} else {
alert("Object is not created!");
}
} catch (ex) {
alert("Error message is: " + ex.Description);
}
</script>
</body>
</html>
... but when I run the page, it generates an error of "undefined" (from the catch(ex) block). Any ideas? Thanks in advance ....... Bob
Your Codebase has to be a url, not just a filename. If your file is in C:\inetpub\myCabFiles\ActiveXSetup.cab, and your website is in C:\inetpub, then codebase should be something like
codebase="www.mywebsite.com\myCabFiles\ActiveXSetup.cab"

Model properties not set when returning to the controller for post

I'm going blind staring at this. When I click save on the view, the model being sent to the save method of the controller has no values set, they're all default values.
What am I missing? I'm actually using the exact same technique from another project...
The data is populated just fine in my view, I can edit it and click save, the code enters the SetSiteTerms method in the controller but has none of the data from the view. :-(
I know this is something simple and dumb but I just can't see it yet.
Model:
Imports System.ComponentModel.DataAnnotations
Imports System.Runtime.Serialization
<KnownType(GetType(SiteToA))> _
Public Class SiteToA
<ScaffoldColumn(False)> _
Public Property ID As Integer = 0
Public Property AgreementHTML As String = String.Empty
Public Property AgreementName As String = String.Empty
Public Property IsActive As Boolean = False
Public Sub New()
MyBase.New()
End Sub
End Class
View:
<%# Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl(Of Community_Portal_Admin.SiteToA)" %>
<% Using Html.BeginForm("SetSiteTerms", "SiteToA", FormMethod.Post, New With {.id = "SiteTermsForm"})%>
<div class="gridFrame">
<% Html.Telerik().EditorFor(Function(m) m.AgreementHTML) _
.Name("AgreementHTML") _ ' Name must be the same as the property name in the model
.Encode(True) _
.HtmlAttributes(New With {.style = "height:300px;"}) _
.Render()%>
<br />
<div class="smallFrameLeft">
<%: Html.ActionLink("Cancel", "Index", "Home", Nothing, New With {.class = "t-button", .Style = "font-size:12px;"})%>
</div>
<div class="smallFrameRight">
<input type="submit" value="Save" class="t-button" />
</div>
</div>
<% End Using%>
Controller:
Imports Telerik.Web.Mvc
Public Class SiteToAController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Dim setting As SiteToA
Try
setting = SiteToARepository.One(Function(d) d.IsActive = True)
ViewData.Model = setting
Return PartialView()
Catch ex As Exception
Throw
End Try
End Function
<HttpPost()> _
Function SetSiteTerms(ByVal model As SiteToA) As ActionResult
Dim setting As SiteToA
Try
setting = SiteToARepository.One(Function(d) d.ID = model.ID)
TryUpdateModel(setting)
If Not SiteToARepository.Update(setting) Then Throw New Exception("There was a problem during update")
Return PartialView()
Catch ex As Exception
Return PartialView()
Finally
If Not setting Is Nothing Then
setting.Dispose()
setting = Nothing
End If
End Try
End Function
End Class
EDIT:
I've updated my view and controller. Any ideas why my model is populated, can be editing in the view but when I post with the save button, the model sent to the controller has no data???
I've updated the orginal post to show the answer provided by Telerik, also my problem with the rest of the model was a silly missing : lol

Do need to databind in gridview?

If dt_grid.Rows.Count > 0 Then
dt_grid.DataSource = dt_grid
Else
MessageBox.Show("Not Found Data")
End If
I know that if get datatable in gridview.datasource,ever write gridview.Databind.But I found coding of my friend. He write only get datatable in gridview.datasource but no write gridview.dataBind. Therefore, his coding is not error. Why? Don't need to dataBind?
Are you sure your friend is not using the DataSourceID property?
Here is the difference from MSDN:
When the DataSourceID property is set (instead of the DataSource property), the data-bound control automatically binds to the data source control at run time.
Please take a look at this article and this one.
Hope it helped.
I took the time to do a small example to demonstrate that you need to call DataBind() on a normal asp.net gridview in order to render its data.
If your friend is not calling this, I am guessing that he is binding the grid to a data source in the .aspx code (to a SQLDatasource, on even an ObjectDataSource) and he is modifying that datasource in the code.
Please take a look at the following example:
The default.aspx page:
<%# Page Title="Home Page" Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="GridViewDemo._Default" %>
<form id="form1" runat="server">
<asp:gridview id="GridView1" runat="server">
<Columns>
<asp:BoundField DataField="ID" />
<asp:BoundField DataField="Name" />
</Columns>
</asp:gridview>
</form>
The codebehind for the page: (it is in C# but I think it is relevant to VB as well)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace GridViewDemo
{
public partial class _Default : System.Web.UI.Page
{
public class Entity
{
public int ID { get; set; }
public string Name { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
List<Entity> source = new List<Entity>() { new Entity() { ID = 1, Name = "First" }, new Entity() { ID = 2, Name = "Second" } };
GridView1.DataSource = source;
GridView1.DataBind();
// if you comment this line and run, the gridview is not rendered
}
}
}
Let me know if this answered your question.