views:

466

answers:

6

I have a versioned model:

public class VersionedModel
{
    public Binary Version { get; set; }
}

Rendered using

<%= Html.Hidden("Version") %>

it gives:

<input id="Version" name="Version" type="hidden" value="&quot;AQID&quot;" />

that looks a bit strange. Any way, when the form submitted, the Version field is always null.

public ActionResult VersionedUpdate(VersionedModel data)
{ 
    ...
}

How can I pass Version over the wire?

EDIT:

A naive solution is:

public ActionResult VersionedUpdate(VersionedModel data)
{ 
    data.Version = GetBinaryValue("Version");
}

private Binary GetBinaryValue(string name)
{
    return new Binary(Convert.FromBase64String(this.Request[name].Replace("\"", "")));
}
A: 

You may need to use binding to get a strongly-typed parameter to your action method.

Try rendering using:

  <%=Html.Hidden("VersionModel.Version")%>

And defining your action method signature as:

public ActionResult VersionedUpdate([Bind(Prefix="VersionModel")] VersionedModel data)
  {     
      ...
  }
Lee D
I have no problems with other properties of the VersionModel, only with Version property. It should be some thing specific to Binary data type.
alex2k8
+1  A: 

I think the problem with not seeing it in the bound model on form submission is that there is no Convert.ToBinary() method available to the model binary to restructure the data from a string to it's binary representation. If you want to do this, I think that you'll need to convert the value by hand. I'm going to guess that the value you are seeing is the Base64 encoding of the binary value -- the output of Binary.ToString(). In that case, you'll need to convert it back from Base64 to a byte array and pass that to the Binary() constructor to reconstitute the value.

Have you thought about caching the object server-side, instead? This could be a little tricky as well as you have to detach the object from the data context (I'm assuming LINQ) or you wouldn't be able to reattach it to a different data context. This blog entry may be helpful if you decide to go that route.

tvanfosson
Thank you for your ideas, seems you vote for my "naive solution". According to server-side caching - I would like to avoid this.
alex2k8
+1  A: 

Related posts I found.

1) http://geekswithblogs.net/frankw/archive/2008/08/29/serialization-issue-with-timestamp-in-linq-to-sql.aspx

Suggests to turn 'Binary Version' into 'byte[] Version', but some commenter noticed:

The problem with this approach is that it doesn't work if you want to use the Table.Attach(modified, original) overload, such as when you are using a disconnected data context.

2) http://geekswithblogs.net/AndrewSiemer/archive/2008/02/11/converting-a-system.data.linq.binary-or-timestamp-to-a-string-and-back.aspx

Suggests a solution similar to my 'naive solution'

public static string TimestampToString(this System.Data.Linq.Binary binary) 
{ ... }

public static System.Data.Linq.Binary StringToTimestamp(this string s)
{ ... }

3) http://msdn.microsoft.com/en-us/library/system.data.linq.binary.aspx

If you are using ASP.Net and use the SQL Server "timestamp" datatype for concurrency, you may want to convert the "timestamp" value into a string so you can store it (e.g., on a web page). When LINQ to SQL retrieves a "timestamp" from SQL Server, it stores it in a Binary class instance. So you essentially need to convert the Binary instance to a string and then be able to convert the string to an equivalent Binary instance.

The code below provides two extension methods to do this. You can remove the "this" before the first parameter if you prefer them to be ordinary static methods. The conversion to base 64 is a precaution to ensure that the resultant string contains only displayable characters and no escape characters.

public static string ConvertRowVersionToString(this Binary rowVersion) {
  return Convert.ToBase64String(rowVersion.ToArray());
}
public static Binary ConvertStringToRowVersion(this string rowVersion) {
  return new Binary(Convert.FromBase64String(rowVersion));
}
alex2k8
A: 

This post http://forums.asp.net/p/1401113/3032737.aspx#3032737 suggests to use LinqBinaryModelBinder from http://aspnet.codeplex.com/SourceControl/changeset/view/21528#338524.

Once registered

protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(Binary), new LinqBinaryModelBinder());
}

the binder will automatically deserialize Version field

public ActionResult VersionedUpdate(VersionedModel data) 
{ ... }

rendered this way:

<%= Html.Hidden("Version") %>

(See also http://stephenwalther.com/blog/archive/2009/02/25/asp.net-mvc-tip-49-use-the-linqbinarymodelbinder-in-your.aspx)

alex2k8
A: 

There are many ways like here

byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks]; _store.Version = new System.Data.Linq.Binary(b)

(make sure you bind exclude your version),

But the best way is to let the DB handle it...

A: 

There are many ways like here

byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks]; _store.Version = new System.Data.Linq.Binary(b)

(make sure you bind exclude your version),

But the best way is to let the DB handle it...