Breeze SaveChanges issue with Ie10

Every new technology is an hard path , an high mountain to climb.

I’m working to an MVC project with ASP.NET 4.5 , Breeze and Angular, authentication done with the new ASP.NET Identity, Entity Framework 6.

The big problem , for the average developer (me) , is:

  • For Microsoft, on MSDN you can find a lot of verbose pages about the syntax: an simple CRUD example using these technologies , add update delete of records, is hard to find.
  • For thirdy parties technologies you can find abstruse , overcomplexed samples ; ma still there is a lack of a simple table management with CRUD operations.

In every case the samples simply ignore (at the least the ones that i discover with Google) the everyday questions with concurrency : another user could have deleted the record that you are trying to save, or you are trying to save a record of a table where there is an unique index for a field.

Ok , this was the rant, now the problem.

The code is about the update of a record in a Vehicle Classes table (ClassiMezzi).

Using Breeze, in a BreezeController (a class decorated with “[BreezeController]“) the typical sample for an update is

[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
    return _repo.SaveChanges(saveBundle);
}

This works with Ie11, the latest Firefox, Chrome, Safari; _repo is an repository object that at the end calls the Entity Framework context provider (in our sample EFContextProvider<ClassiMezziContext>)

But if you try to use this method for adding a new record on a table where there is an index UNIQUE, there are troubles with the error messages using Internet Explorer 10.

For these new apps i simply don’t consider Ie < 10; if you are still using Ie6 , Ie7.. time to upgrade …but to ignore the previous version is a bit excessive, for me: i test everything with the latest Firefox, Chrome also under Linux Android and Mac, for Ie to test the latest version and the previous seems reasonable.

And so, testing the code with multiuser issues (record deleted from another user, check constraints, UNIQUE indexes) i discovered the problem.

From the javascript side , the controller is called with an Ajax call with callbacks for success or failure:

function saveFailed(error) {
    try {
        manager.detachEntity(service.ClasseMezzoEntity);
    }
    catch (ex) { }
    service.ClasseMezzoEntity = null;
    if (error.httpResponse.status === 401 || error.httpResponse.status === 403) {
        logError(localize.localizeText("UnauthorizedOperation"), null, true);
        return;
    }
    //var strMsg = breeze.saveErrorMessageService.getErrorMessage(error).toLowerCase(); old version ok with Ie11 , not Ie10
    var strMsg = error.httpResponse.data.Errors[0].toLowerCase();
    if (strMsg.indexOf("entities may have been modified or deleted since entities were loaded") > 0) {
        logWarning(localize.localizeText("AnotherUsrHasChangeData"), null, true);
        return;
    }
    if (strMsg.indexOf("ix_classimezzi") > 0) {
        logWarning(localize.localizeText("ClassNameDuplicated"), null, true);
        return;
    }
    if (strMsg.indexOf("errdelete:anotheruser") > 0) {
        logWarning(localize.localizeText("AnotherUsrHasDeleteData"), null, true);
        return;
    }
    //  other code for unknown error management
    var msg = breeze.saveErrorMessageService.getErrorMessage(error);
    // etc.
};
 
function saveClasseMezzo() {
    service.isSaving = true;// see at the end of this module
    service.lastSaveSuccess = true;
    return manager.saveChanges()
        .catch(saveFailed)
        .then(saveClasseMezzoAttemptDone);
};

For example we try to add another ClasseMezzo (Vehicle class) with the same name of an existing item on the the db table.

With Ie11 and other latest browsers the first controller code is ok , and if our ajax call fails because the UNIQUE index the first

var strMsg = breeze…. commented code works perfectly.

But while with Ie11 etc. the error.message in javascript contains the string “Cannot insert duplicate key row …” with the index name that helps to manage the error (in this sample the index name is “ix_classimezzi”) in Ie10 we get


That is an anonymous “An error has occurred” that can’t help to manage the error, and no trace of the original SQL error in httpResponse: a big trouble if i would to say to the customer “you are trying to insert an duplicate item” because could be another thing , for example an SQL check violation.

The problem is the simple approach in the WebApi2 controller.

In order to manage correctly the errors coming from multiuser issues the WebAPI2 controller code must be:

[HttpPost]
[Authorize(Roles = "PowerUser")]
public SaveResult SaveChanges(JObject saveBundle)
{
    SaveResult objRes = null;
    List<object> objErr = null;
    var classimezziList = JsonConvert.DeserializeObject<List<ClassiMezzi>>(saveBundle.SelectToken("entities").ToString());
    try
    {
        objRes = _repo.SaveChanges(saveBundle);
        return objRes;
    }
    catch (Exception ex)
    {
        var keyMappings = new List<KeyMapping>();
        objErr = new List<object> { JsonConvert.SerializeObject(ex.Message) };
        return new SaveResult()
        {
            Entities = classimezziList.Cast<object>().ToList(),
            Errors = objErr,
            KeyMappings = keyMappings
        };
    }
}

Let’s examine the code.

We pass to the controller an JSON object , that we want deserialized in order to correctly manage the error; note in the catch management code: is explicitly created an SaveResult object , instead of the automatic creation.

Setting the Errors field to something != null , in our case the error message serialization, we cause the call of the javascript failure callback , and in the javascript failure code the message must be read as

var strMsg = error.httpResponse.data.Errors[0].toLowerCase();

because when the code is falling back we have this , now:


So we can manage the things as in the next rows.

This is valid also for Ie11 , and Firefox, Chrome under Windows, Linux, Mac, Android.

At least, this is the situation with the current latest Breeze (1.3.8)

The requested resource does not support http method ‘POST’

After a life of web sites developed with Web Forms, now i’m working with MVC.

Not a basic MVC, but SPA apps using Angular, Breeze, Twitter Bootstrap.. an huge jump.

In the Controller folder of my solution i was thinking to create an utilities controller, in this case for the logging of javascript errors, paging utilities, and so on.

So i initially created a class as:

public class ServicesController : ApiController
{
	[HttpPost]
	public void SubmitError(string jsRespoText, string jsstatus, string jssource)
	{
		ExceptionUtility.LogJsExceptionFile(jsRespoText, jsstatus, jssource);
	}

	[HttpGet]
	public JsonGenResponse CreatePagerStdTable(int startRowIndex, int totalCount, int pageSize, string jsLoadDataFunName, string Filter, string QueryType)
	{
		// this will be another post…
	}
}

For the HttpGet , no problem.

When i tried from Fiddler the HttpPost method i got the error written in the subject of this post.

A Controller decorated with [BreezeController] works as POST, and it was tested.. but it uses a JObject parameter, i noticed.

The POST problem pops out when you try to use primitive (string, int..) parameters in a Web API call instead of an object.

A solution could be to use [FromBody], with this attribute WebAPI search the attribute:value in the request body.

But there is a problem : is not possible to specify more than one “[FromBody]” , so is not possible to write:

public void SubmitError([FromBody]string jsRespoText, [FromBody]string jsstatus, [FromBody]string jssource)

The solution is to create a class, in my case

public class JsErrorData
{
    public string jsRespoText { get; set; }
    public string jsstatus { get; set; }
    public string jssource { get; set; }

}

And then write the method as

[HttpPost]
public void SubmitError(JsErrorData jsObjErr)
{
    ExceptionUtility.LogJsExceptionFile(jsObjErr.jsRespoText, jsObjErr.jsstatus, jsObjErr.jssource);
}

The javascript caller:

function logJsError(responseText, status, source, callback) {
    var ajaxImpl = breeze.config.getAdapterInstance("ajax");
    ajaxImpl.ajax({
        type: "POST",
        contentType: "application/json;charset=UTF-8",
        url: strBaseHttp + "api/Services/SubmitError",
        data: "{'jsRespoText': '" + responseText.replace(/'/g, '') + "','jsstatus':'" + status + "','jssource':'" + source + "'}",
        success: function (html) {
            callback(html);
        },
        async: true
    });
}

Now HttpPost is working.

Categories: .NET, JQuery, MVC, SPA

Good idea

Categories: Uncategorized

Oracle RAC Linked server in Sql 2014 64 bit

I was needing to create a linked server from SQL Server 2014 64 bit, on a pc with Windows 8.1 64 bit , to an Oracle 10.2.0.3 configured in RAC (Real Application Clusters).

The RAC configuration is composed from 3 servers .

The first step is to install the Oracle software from http://www.oracle.com/technetwork/database/windows/downloads/index-090165.html

Here must be downloaded 64-bit ODAC 12c Release 2 (12.1.0.1.2) for Windows x64 , the file ODAC121012_x64.zip because there is an guided installer.

After a while it starts then use the default choice, that is the Oracle Data Access Components which installs the Data Provider for .NET, Oracle Provider for OLEDB, Oracle Services for Microsoft Transaction Server, Oracle instant client.

Then use the Next button accepting all defaults until the end.

At the end there is a wizard for the compilation of tnsnames.ora file, but in this case we are working with a RAC and the wizard cannot manage this configuration.

After the installation is recommended to reboot, then we should see in Sql Management Studio the OraOLEDB provider listed:


By default in C:\app\studio\product\12.1.0\client_1\Network\Admin there is our TNSNAMES.ORA file

We must know the NETBIOS or the IP of the servers in RAC and the name of the Oracle instance, in our case TRAFSRV for example.

So the TNSNAMES.ORA , indicating the IP for each or our 3 RAC server, should be :

TRAFSRV =
  (DESCRIPTION =
   (LOAD_BALANCE = ON)
   (FAILOVER = ON)
   (ADDRESS_LIST =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 10.86.13.19)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = 10.86.13.21)(PORT = 1521))
    (ADDRESS = (PROTOCOL = TCP)(HOST = 10.86.13.23)(PORT = 1521))
   )
   (CONNECT_DATA =
    (SERVICE_NAME = trafsrv.world)
    (FAILOVER_MODE =
     (TYPE = SESSION)
     (METHOD = BASIC)
     (RETRIES = 5)
     (DELAY = 3)
    )
   )
  )

It should be verified that the 1521 port is opened in the firewall, in both Sql and Oracle servers.

Now we can create the linked server , for example

USE [master]
GO
EXEC master.dbo.sp_addlinkedserver @server = N'ORAARTA33', @srvproduct=N'Oracle', @provider=N'OraOLEDB.Oracle', @datasrc=N'TRAFSRV'
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'ORAARTA33',@useself=N'False',@locallogin=NULL,@rmtuser=N'ORACLEUSER',@rmtpassword='ORACLEUSERPWD'

In this sample ORAARTA33 is the name of the linked server, it there are no problems we should see


Categories: .NET, Oracle, SQL Server

Asp:ButtonColumn not working in Ie11

I was working to an old VB.NET web application with Visual Studio 2010 , .NET 4.0; the solution for tables uses asp:DataGrid

Until Internet Explorer 10 all ok, with Ie11 the asp:ButtonColumn inside an asp:DataGrid was not working, clicking the link nothing.

It seems that the .NET 4 framework does not work well with Ie11 , and the update to .NET 4.5 was not an option (Windows Server 2003).

With the latest updates Ie11 was still recognized as Mozilla 0.0

The solution is to add an App_Browser folder

And then inside the folder create an .browser file with this content:

<browsers>
  <browser id="IE11" parentID="Mozilla">
    <identification>
      <userAgent match="Trident\/7.0; rv:(?'version'(?'major'\d+)(\.(?'minor'\d+)?)(?'letters'\w*))(?'extra'[^)]*)" />
      <userAgent nonMatch="IEMobile" />
    </identification>
    <capture>
      <userAgent match="Trident/(?'layoutVersion'\d+)" />
    </capture>
    <capabilities>
      <capability name="browser" value="IE" />
      <capability name="layoutEngine" value="Trident" />
      <capability name="layoutEngineVersion" value="${layoutVersion}" />
      <capability name="extra" value="${extra}" />
      <capability name="isColor" value="true" />
      <capability name="letters" value="${letters}" />
      <capability name="majorversion" value="${major}" />
      <capability name="minorversion" value="${minor}" />
      <capability name="screenBitDepth" value="8" />
      <capability name="type" value="IE${major}" />
      <capability name="version" value="${version}" />
    </capabilities>
  </browser>

  <!-- Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11,0) like Gecko -->
  <browser id="IE110" parentID="IE11">
    <identification>
      <capability name="majorversion" match="11" />
    </identification>

    <capabilities>
      <capability name="ecmascriptversion" value="3.0" />
      <capability name="jscriptversion" value="5.6" />
      <capability name="javascript" value="true" />
      <capability name="javascriptversion" value="1.5" />
      <capability name="msdomversion" value="${majorversion}.${minorversion}" />
      <capability name="w3cdomversion" value="1.0" />
      <capability name="ExchangeOmaSupported" value="true" />
      <capability name="activexcontrols" value="true" />
      <capability name="backgroundsounds" value="true" />
      <capability name="cookies" value="true" />
      <capability name="frames" value="true" />
      <capability name="javaapplets" value="true" />
      <capability name="supportsCallback" value="true" />
      <capability name="supportsFileUpload" value="true" />
      <capability name="supportsMultilineTextBoxDisplay" value="true" />
      <capability name="supportsMaintainScrollPositionOnPostback" value="true" />
      <capability name="supportsVCard" value="true" />
      <capability name="supportsXmlHttp" value="true" />
      <capability name="tables" value="true" />
      <capability name="supportsAccessKeyAttribute" value="true" />
      <capability name="tagwriter" value="System.Web.UI.HtmlTextWriter" />
      <capability name="vbscript" value="true" />
    </capabilities>
  </browser>
</browsers>
Categories: .NET, Ajax, Visual Studio 2010

BI for Visual Studio 2013

Still unavailable…someday at this address.

Update 05/23 : available !

Categories: BI, SQL Server, SSIS

OData services

My previous post is half the story.

The original intent was to use Entity Framework and build an WCF data service, but with the latest EF 6.1.0 it seems that is no more possible.

Microsoft is now strongly oriented to the new OData religion: i discovered that there is a NUGet project for a bridge between WCF and EF6 in a alpha stage, and it seems abandoned from months.

I tried, but it installs an EF6 prerelease, and in every case i was not able to obtain something of working.

In my previous post i was able to create an EF model, and then i added an WCF Data Service 5.6.

But it was not working , trying to launch the .svc file i got

“The server encountered an error processing the request. See server logs for more details.”

I ended up with this code:

namespace NorthwindWeb
{
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class NorthwindCustomers : DataService<NorthwindEntities1>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.UseVerboseErrors = true;
            config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
        }
    }
}

The ServiceBehavior decoration gives detailed error infos , which was:

“The server encountered an error processing the request. The exception message is ‘Expression of type ‘System.Data.Entity.Core.Objects.ObjectContext’ cannot be used for return type ‘System.Data.Objects.ObjectContext”

It seems that i should use EntityFrameworkDataService<NorthwindEntities1> instead of DataService, but this object is apparently not available in EF6 object model or somewhere else, and i’m not the best WCF/EF expert.

I’m thinking to the ones (also me) that had written a lot of WCF code using EF…they should rewrite all? or the projects needs to be “closed”, no more NuGet updates ?

This is another case where “googling” i find that i’m not alone.

Ok , waiting for the next Microsoft change of mind (“throw away OData: is old, unsecure, blah blah.. now there is <new buzzword>”) i wrote the OData web service with Web API…sometimes i envy the COBOL programmers that are maintaining ancient software where the screens are painted with | and -.

So from Visual Studio 2013 new project ->ASP.NET Web Application


Then in the next wizard step choose the Empty template but add Web API:


This is the moment of adding via NuGet (TOOLS->NuGet Package Manager->Manage NuGet packages for Solution.. the Entity Framework and OData.


 
 


Now is recommended to clic on Updates and update all of the NuGet components:


Now if we want to add an Data Model there is still the trouble described in the previous post; so copy the sample connection string in web.config (also from the mentioned previous post) changing the name , data source, initial catalog and so on.

We still use Northwind as sample, so we add to the solution an ADO .NET Entity Data Model that in our sample we call NorthwindModel.edmx

In order to avoid mistakes , is better to leave checked the creation of a new connection string, that will be the one used:


In this sample we still use only the Customers table


With a Model Namespace = NorthwindModel

Do a Build->Rebuild all, otherwise in the next step Visual Studio complains about an error.

In the automatically generated Controllers folder (in the Visual Studio solution) right clic and add a controller:


We add “Web API2 OData with actions, using Entity Framework”.

In the next step by simply clicking on the drop downs and writing “CustomersEntity” in Controller name we can set the controller as in figure:


In the Controllers folder now we have a CustomersEntityController.cs class: Visual Studio and his template engine is so gently that is generated also an sample of code:


The commented code must be copied in WebApiConfig.cs class under the App_Start folder, so at the end we have

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.OData.Builder;
using NorthwindSvc;
 
namespace NorthwindSvc
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
 
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Customers>("CustomersEntity");
            config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}

Ok, now we can launch the site.

Tipically this does nothing, complaining that a default document is not configured for the requested URL, and directory browsing is not enabled on the server.

But in CustomersEntityController.cs we can see examples of calling the web service, so if we add /odata/CustomersEntity to the browser address (for example http://localhost:11775/odata/CustomersEntity)

we get an JSON file with the records of the Customers table:


This with Google Chrome, Internet Explorer requires to download the JSON file.

Observing the generated code we can read

// GET odata/CustomersEntity(5)
[Queryable]
public SingleResult<Customers> GetCustomers([FromODataUri] string key)
{
    return SingleResult.Create(db.Customers.Where(customers => customers.CustomerID == key));
}

This means that we can write /odata/CustomersEntity(‘ALFKI’) and we get only the corresponding record.

With OData are coming for free many interesting features regarding the querystring

For example we can write


That is we filter our data for Country = Mexico and we need only the company name and the fax; the result:


The condition could be complex, for example we can specify &filter=Country eq ‘Mexico’ and CustomerID eq ‘ANTON’

A reference of the OData query options at these addresses:

http://msdn.microsoft.com/en-us/library/gg312156.aspx

http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

Categories: .NET, MVC, OData, Visual Studio 2013

Microsoft.SqlServer.Management.Sdk.Sfc not found

In theory within an updated, state of the art system it should be all ok, but it is not always so.

I’m using a brand new installed windows 8.1 , with Visual Studio 2013 and SQL Server 2014; all with the latest updates.

In a new Web application i was adding an ADO.NET Entity Data Model, operation that i done a lot in the past.


However, this time when creating the new connection to Northwind (my original intent is to create a web service for test) i got the error:


Searching on Internet i have seen that i’m not alone with this problem.

Could be the combination of Visual Studio 2013 with the very new SQL 2014? could be that until Visual Studio 2012 + SQL 2012 there was not this problem? i don’t have a pc with Visual studio 2012 and i don’t have the time to create an install an vm to verify these conditions.

On c:\windows\assembly in windows 8.1 i can see


Effectively no Microsoft.SqlServer.Management.Sdk.Sfc version=11.0.0.0

Could be that this is a bug and it will be fixed, so i tried on a vm with Visual Studio 2010: here no problems for the creation of the model…

But in every case what does this part of the wizard? nothing more than add a connectionstring in the relative web.config section.

In the Visual Studio 2010 project i tried to connect the same Northwind on the same server which i tried to connect in the Visual Studio 2013 solution; in this case it was created this connectionstring:

<add name="NorthwindEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=mysql2014svr;initial catalog=Northwind;persist security info=True;user id=sa;password=thepwd;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

I pasted this connection string in the connectionstrings section of the Visual studio 2013 web.config, so the connection is already in place when adding the ADO.NET Data Model in the Visual Studio 2013 project:


Moreover, it can set my data model without problems:

Categories: .NET, Visual Studio 2013, WCF

Network path was not found error

I’ m working with networked computers from near 30 years, and with Microsoft networks from 20.

I still remember the old good times of Windows 3.11 (not For Workgroup) and the problems of a network between Win 3.11 and Windows 95 clients: there was no Internet, the network adapters were coming by floppy disks in the adapter box or by connecting to a remote BBS for the latest update.

It was the time of networking with Lantastic (i still remember the infamous “ding” sound when the network was clogged…) : so sometimes the best solution was a Novell Netware 286 dedicated server; but there was the problem in the client PCs , loading the Novell drivers chkdsk were erroneously reporting severe problems in the file system.

Now many problems are gone: i prepared a server with Windows 2012 Standard some months ago and i discovered that from the ASRock BIOS is possibile not only to download the requested drivers on a USB key (even if i found that if the USB key has no sufficient space the download apparently is anyway OK..) but if the server is connected to a working Internet connection is possible to require assistance to the producer, from the BIOS !

I was thinking to the same situation (network card unacknowledged) at the times when i was installing Windows NT 4.0 Workstation.

Now with the same server, reformatted and installed with Windows Server 2012 R2, no problem for the network card, no need for external download: Windows 2012 R2 has directly acknowledged the network card.

But there are still issues with Microsoft networking .. for example i installed an 2012 R2 as domain controller with address 192.168.0.2, the ADSL modem is 192.168.0.1 and in practice is the DNS.

Then i installed another server 192.168.0.4 dedicated to SharePoint 2013 (never install SharePoint on a domain controller) and the first thing is to join this server to the domain controller.

Tipically you go to Control Panel->System, change settings from workgroup to domain, write the domain name and click ok: after inserting when prompted the user “administrator” of the DC with the password .. a long wait … and then the error.

Ok, i’m primarily a developer so i don’t know very well some system arguments, but searching on Google i noticed that the error reported in the subject of this post is not so rare.

The solution is to set as DNS in the adapter property of the client not the ADSL modem address but the one of the DC : in my sample 192.168.0.2 instead of 192.168.0.1

Done this, the domain is joined without a long wait and the internet connection is working.

There are other possible issues to verify: in the adapter property verify if is activated

“Client for Microsoft Networks”


and the services “Remote Registry” and “TCP/IP NetBIOS Helper” are running on DC and server that you would join to the DC.

Conclusion: a little hint from the OS when you get this error?

Categories: SharePoint, Uncategorized
Follow

Get every new post delivered to your Inbox.