Tuesday, July 29, 2014

Display Created by fields in Custom SharePoint List

One challenge to getting a custom form to display what you want is understanding the eccentricities of SharePoint Designer and the SharePoint storage.  I had a custom list which needed to display the created by and modifed by data.  These fields needed to be displayed on the main form along with the other data items.  This information is normally parked in the footer of the form.  This can be done by using the SharePoint:CreatedModifiedInfo  control item.  One thing to note is that the fields in Sharepoint are stored internally with different names:

Created By = @Author
Modified By = @Editor

Code to add to your custom form:

<tr>
         <td valign="top" class="ms-formlabel"><nobr>Created by</nobr></td>
         <td valign="top" class="ms-formbody">
             <SharePoint:CreatedModifiedInfo ControlMode="Edit" runat="server">
             <CustomTemplate>
                 <SharePoint:FormField FieldName="Author" runat="server" ControlMode="Display" DisableInputFieldLabel="true" /><br/>
                 <SharePoint:FieldValue FieldName="Modified" runat="server" ControlMode="Display" DisableInputFieldLabel="true"/>
             </CustomTemplate>
             </SharePoint:CreatedModifiedInfo>
         </td>
     </tr>

Custom Edit List Form Modified By field is blank -

Custom Form Does Not Display “Created By” value


I was customizing a sharepoint list today and customer asked for a modification to the New and Edit forms for the list.  I was using Designer to accomplish the task and was able to get most of it working.  The customer had asked for a field on the edit form to show the Modified by field.  This is the standard canned field which is part of every list in SharePoint.  I thought no problem I just get the internal field name and use the <xsl:value-of select="@Editor"/>. 

Challenge:

Each time I would load the edit form the field would resolve to empty.  This made no sense and really drove me crazywhile I tried to understand the problem. 

Sample:
<tr>
      <td valign="top" class="ms-formlabel" width="190px">
       <H3 class="ms-standardheader">
        <nobr>Modified By</nobr>
       </H3>
     <!--Always Blank --/>
       <xsl:value-of select="@Editor" disable-output-escaping="yes"/>
      

      </td>
      <td valign="top" class="ms-formbody" width="400px">
       <SharePoint:FormField runat="server" id="ModifiedByID" ControlMode="New" FieldName="Editor" __designer:bind="{ddwrt:DataBind('u','ModifiedByID','Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Editor')}"/>
       <SharePoint:FieldDescription runat="server" id="ff7description{$Pos}" FieldName="Editor" ControlMode="Edit"/>
      </td>
     </tr>

Solution:

It helped me to look at the entire form and pay close attention to the syntax for the FormField control.
This includes the attribute ControlMode.  This tells the form control what state it is currently in.  (New,Edit,Display)  The key mistake I had made was to set this controlmode attribute to New instead of Edit.Once I set the controlmode attribute to Edit the value began to be passed to the form and displayed.

Corrected:
<tr>
<td valign="top" class="ms-formlabel" width="190px">
<H3 class="ms-standardheader">
<nobr>Modified By</nobr>
</H3>
<!--Always Blank --/>
<xsl:value-of select="@Editor" disable-output-escaping="yes"/>


</td>
<td valign="top" class="ms-formbody" width="400px">
<SharePoint:FormField runat="server" id="ModifiedByID" ControlMode="Edit" FieldName="Editor" __designer:bind="{ddwrt:DataBind('u','ModifiedByID','Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Editor')}"/>
<SharePoint:FieldDescription runat="server" id="ff7description{$Pos}" FieldName="Editor" ControlMode="Edit"/>
</td>
</tr>

Wednesday, July 23, 2014

Xamarin and Sole Source justification

Great post by Tim Anderson and Andy Dent about Xamarin vs. other competitors

- Xamarin (+ MVVMCross) ideal cross product solution. https://github.com/MvvmCross/MvvmCross

- The purpose of PhoneGap is to allow HTML-based web applications to be deployed and installed as native applications

- The goal of Titanium Mobile is to provide a high level, cross-platform JavaScript runtime and API for mobile development (today we support iOS, Android, and the browser, with BlackBerry 10 and Windows Phone coming soon and eventually, respectively).


Source:

http://stackoverflow.com/questions/17249500/xamarin-2-0-vs-appcelerator-titanium-vs-phonegap

Friday, July 18, 2014

JSON deserializing and serializing

Convert XML to JSON

http://www.utilities-online.info/xmltojson/

JSON convert between XMLNode and json

XmlNote myXmlNode = JsonConvert.DeserializeXmlNode(myJsonString);
// or .DeserilizeXmlNode(myJsonString, "root");
// if myJsonString does not have a root
string jsonString = JsonConvert.SerializeXmlNode(myXmlNode);

SDK documentation
http://james.newtonking.com/json/help/index.html

Wednesday, July 16, 2014

Connection string sytnax for IIS to SQL Server connection.

I always forget the syntax for connnection strings in my applications.  The guys at connectionsstrings.com do a great job but stumbled across another way to get at the correct syntax.


The steps below.


1.     Right-click an empty spot on the desktop and choose NEW, TEXT DOCUMENT from the context menu


2.     Save it with a .udl extension, and click yes when it asks are you sure.


3.     Double-click the new udl file you just created. It will open a dialogue. Go to the Provider tab, and choose the appropriate provider.


4.     Go to the Connection tab and fill in the server name and database name, and choose NT authentication (or use a specific username and password, which is SQL authentication). Now click Test Connection. If it works, you're ready to click OK and move on to the final step. If it doesn't you need to resolve permission issues, or you've mis-typed something.

5.     Now right-click the file on the desktop and open it in notepad. It will display the connection string that you can copy and paste to wherever you need it.

Identity Impersonation with Classic ASP

The ideal:

I have written before about using impersonation in IIS.  That was using the tools provided in .Net Framework.  This allows a web application to provide dedicated account access to a database.  Thus the application can prompt a user to login with their Windows credentials and a separate service account can be used to support all data access between that web application and the database.  This makes the application most secure as it restricts database access to a single account.  Auditing also becomes much simpler.

The reality:

Now it is great to think about how easy it is in .Net.  The reality is that there are still classic ASP applications which are simply being ported forward to IIS7/7.5.  I cringe when a customer asks for this.  They can't understand why the software has to be updated.  One issue is impersonation.

I had a customer wanting to port the application forward and just assuming that they could apply all the security "boxes" just like a .Net application.  Sadly this is not the case for classic ASP.  It does not have a native mechanism to support impersonation. 

"As most of you know ASP executes under the guise, typically, of the IUSR_ account in IIS (IIS_IUSRS group for IIS 7) which has a very few permissions to do anything on the system (in most cases anyway). "

So what can you do?  I found some great help from Doug Parsons over at Wrox.com


The fix:

You can write a ActiveX dll which you register on your IIS box.  This dll is then used by your ASP application each time you want to access the database. 

Using Statements
csharp Code:
using System; using System.Runtime.InteropServices;
Class Definition
csharp Code:
namespace Impersonate
{[indent]public class UserLogon
{[indent][DllImport("advapi32.dll", SetLastError=true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

[DllImport("advapi32.dll")]
public static extern int ImpersonateLoggedOnUser(IntPtr hToken);

[DllImport("advapi32.dll")]
public static extern bool RevertToSelf();

[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);

private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
public void Logon(string strAdminUser, string strAdminPassword, string strAdminDomain)
{
IntPtr hToken;

RevertToSelf();

LogonUser(strAdminUser, strAdminDomain, strAdminPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out hToken);

ImpersonateLoggedOnUser(hToken);

CloseHandle(hToken);
}
public void Logoff()
{
RevertToSelf();
}
[/indent]}
[/indent]}

In the Solution Explorer locate the AssemblyInfo.cs file underneath the Properties folder of your project (you may need to click the 'Show all Files' button at the top of the solution explorer) and open it. Add the following line to the file:


csharp Code:
[assembly: ComVisible(true)]
Hit Ctrl + Shift + B (Build) to create your assembly.

Start* up a Visual Studio Command Prompt which can, typically, be found in Start -- > Programs --> Visual Studio 2008 --> Visual Studio Tools and navigate to the directory where your assembly is (something like: projectDirectory\bin\debug\) and issue the following command: regasm Impersonate.dll /tlb

*if you are running Win7/8 run this prompt with Admin rights

In your ASP editor (I used Notepad) use the following code to test your assembly:

asp Code:
[size=2]<% Option Explicit Dim objLogon, oFs, oTextFile Set objLogon = Server.CreateObject("Impersonate.UserLogon") objLogon.Logon "username", "password", "domainname" Response.Write("Impersonating") set oFs = server.createobject("Scripting.FileSystemObject") set oTextFile = oFs.OpenTextFile("C:\foo.txt", 2, True) oTextFile.Write "This is some data wrote as a domain user" oTextFile.Close set oTextFile = nothing set oFS = nothing objLogon.Logoff Set objLogon = Nothing Response.Write("Done Impersonating") %> [/size]

Most of this is very basic but there are some things to point out here:

  • Make sure that the call to CreateObject for objLogon has the name of your assembly. The format for the name will be Namespace.Class. If you have followed along using my code then the correct name is Impersonate.UserLogon.
  • Provide a valid username, password, and domain. I have not tried to impersonate a Local User but, I assume, you could simply provide the PC name as the domain and have this work.
  • Make sure that you call LogOff so that the thread reverts back to running as the IUSR account.
Provided that you execute this ASP script under the guise of IUSR, under normal circumstances, the call to create a text file in the root of the C drive should fail with an Access Denied error so that is a good case to test out our impersonation assembly. As you can see above, a user is impersonated, a file is wrote, and the user is logged off. If all went according to plan you should now see a text file in the root of your C drive! Obviously I am making the assumption that the domain user you are impersonating has the right to create files in the root of the C drive so adjust this test case accordingly.

Pitfalls and Gotchas
  • If you are running IIS 7 on a x64 platform you may get a cryptic "Active X is unable to Create Object". Before you google the problem first start up inetmgr, and locate the Application Pool that your ASP script is running from, right click on it and select 'Advanced Settings' from the context menu. The second option under the General section is 'Enable 32-Bit Applications'; change the value from False to True. If you still get the error, then Google it ;]
  • For testing purposes, I suggest moving your dll out of your debug directory and into another one and then register the dll from there. The reason for this is if you have to make any changes to the dll you will not be able to rebuild your project since the OS will have a lock on the dll in your bin directory.
  • If you need to make changes to your assembly after you have already registered it issue the following command from a Visual Studio command prompt inside the directory your assembly is registered from: regasm /u Impersonate.dll tlb:Impersonate.tlb Make your changes and then re-register the assembly using the regasm from the main tutorial. If, after you have unregistered the dll you are unable to replace the file (Access is denied because the file is in use by another process) start taskmgr and kill the w3wp.exe process (you will need to tick off the 'Show porcesses from all users' checkbox). You should now be able to replace the file.




Source:
C# rework:
http://p2p.wrox.com/classic-asp-basics/77007-solution-impersonation-classic-asp.html

MSDN Original (VB6)
http://support.microsoft.com/kb/248187/en-us

Tuesday, July 15, 2014

Cool tool for JSON to C# classes

This is a great site which reads your Json stream and recommends a C# class to contain the resulting query in your solution.

http://json2csharp.com/

Code Sample: Return Office element from Json query in Windows Phone

I wanted to capture this deprecated piece of code which I no longer need in my phone app.
We are supplying a list of office specific information to the phone client via a JSON query.

Calling Method:


using System.Net.WebClient;
using Newtonsoft.Json.JsonConvert;

private static Dictionary<int, Office> _officeLookup;
private static List<Office> theOffices = new List<Office>();

WebClient webClient = new WebClient();
webClient.Headers["Accept"] = "application/json";
webClient.DownloadStringCompleted +=
              new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new Uri(apiUrl));



private void webClient_DownloadStringCompleted(object sender,             DownloadStringCompletedEventArgs e);
{
      try
      {
           if(e.Result != null)
          {
           var offices = JsonConvert.DeserializeObject<Office[]>(e.Result);
           theOffices = offices.ToList();
           int id = 0;
           foreach(Office office in offices)
           {
                _officeLookup.Add(id,office);
               id++;
             }
          }
         }
         catch (Exception ex)
         {
               //Error handling here
         }


}

Thursday, July 10, 2014

Using progress indicator in windows phone systemtray

I am going to add a progress bar to my existing phone app and found a good explanation at Microsoft's site.  It includes an example for implementing the progress bar programmatically or
declaratively.


Code Behind
using Microsoft.Phone.Shell;

namespace SystemTrayTest
{
    public partial class MainPage : PhoneApplicationPage
    {
        ProgressIndicator prog;

        public MainPage()
        {
            InitializeComponent();

            SystemTray.SetIsVisible(this, true);
            SystemTray.SetOpacity(this, 0.5);
            SystemTray.SetBackgroundColor(this, Colors.Purple);
            SystemTray.SetForegroundColor(this, Colors.Yellow);

            prog = new ProgressIndicator();
            prog.IsVisible = true;
            prog.IsIndeterminate = true;
            prog.Text = "Click me...";

            SystemTray.SetProgressIndicator(this, prog);
        }
    }
}


XAML
<shell:SystemTray.ProgressIndicator>
    <shell:ProgressIndicator IsIndeterminate="True" IsVisible="True" Text="Click me..." />
</shell:SystemTray.ProgressIndicator>

Source:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff626537(v=vs.105).aspx

Wednesday, July 2, 2014

How to load XML file located inside the folder of the application in window phone 8

Problem:

I have some onboard xml files which I needed to load into memory.  I was puzzling over how to load them into memory for use in my app.  I tried using XDocument library but I kept getting the error:
"Cannot find file '/XML Files/A.xml' in the application xap package.

XDocument doc = XDocument.Load( "XML Files/MyXmlFile.xml" );

This was not working.  I tried several variations but still was getting the error every time I ran to code.

Solution:
It turns out that my syntax was not the problem.  I needed to set the properties on the xml file correctly. 

1.) Build Action=Content
2.)Copy to output=Copy if newer (or Copy always).


Source:

http://stackoverflow.com/questions/4538874/how-to-load-xml-file-located-inside-the-folder-of-the-application-in-window-phon