The 0.3 WebJobs SDK broke my parameter bindings - azure-storage

I have the following method definition:
public static void ProcessPackageRequestMessage(
[QueueTrigger(queues.PACKAGE)] PackageRequestMessage message,
[Blob(blobs.PACKAGE + "/{RequestId}_{BlobFile}")] ICloudBlob blob,
[Table(tables.PACKAGE)] CloudTable table,
[Queue(queues.EMAIL)] out PackageEmailMessage packageEmailMessage)
The class PackageRequestMessage is defined as follows:
public class PackageRequestMessage
{
public Guid RequestId { get; set; }
public Guid FactoryId { get; set; }
public string BlobFile { get; set; }
public string SKU { get; set; }
public string EmailAddress { get; set; }
}
In version 0.2 of the SDK, when a JSON message of PackageRequestMessage was posted to the queue, this method was called, and the appropriate Blob was found, based on the parameters in the PackageRequestMessage (RequestId, and BlobFile), and all worked well.
Now, in version 0.3 of the SDK, I get the following error:
System.InvalidOperationException: System.InvalidOperationException: Exception binding parameter 'blob' ---> System.InvalidOperationException: No value for name parameter 'RequestId'
at Microsoft.Azure.Jobs.RouteParser.ApplyNamesWorker(String pattern, IDictionary2 names, Boolean allowUnbound)
at Microsoft.Azure.Jobs.RouteParser.ApplyBindingData(String pattern, IReadOnlyDictionary2 bindingData)
at Microsoft.Azure.Jobs.Host.Blobs.Bindings.BlobBinding.Bind(BindingContext context)
at Microsoft.Azure.Jobs.Host.Runners.TriggerParametersProvider1.Bind()
--- End of inner exception stack trace ---
at Microsoft.Azure.Jobs.Host.Runners.DelayedException.Throw()
at Microsoft.Azure.Jobs.Host.Runners.WebSitesExecuteFunction.ExecuteWithSelfWatch(MethodInfo method, ParameterInfo[] parameterInfos, IReadOnlyDictionary2 parameters, TextWriter consoleOutput)
at Microsoft.Azure.Jobs.Host.Runners.WebSitesExecuteFunction.ExecuteWithOutputLogs(FunctionInvokeRequest request, IReadOnlyDictionary2 parameters, TextWriter consoleOutput, CloudBlobDescriptor parameterLogger, IDictionary2 parameterLogCollector)
at Microsoft.Azure.Jobs.Host.Runners.WebSitesExecuteFunction.ExecuteWithLogMessage(FunctionInvokeRequest request, RuntimeBindingProviderContext context, FunctionStartedMessage message, IDictionary`2 parameterLogCollector)
at Microsoft.Azure.Jobs.Host.Runners.WebSitesExecuteFunction.Execute(FunctionInvokeRequest request, RuntimeBindingProviderContext context)
In the dashboard, the message itself is shown with a valid RequestId present in the JSON, so I'm not sure why it's reported missing.

pianomanjh, I was able to reproduce the issue you are describing and I filed a bug. It seems that this failure only occurs in the blob name pattern, parameter binding is not affected.
The workaround for now is to use string instead of Guid for the property types.

Just found a solution to the blob issue i 0.3.0. Compared to version 0.2.0 you have to define the Blob to FileAccess.Write to make it work. It fixed the issue I described above to be able to stream to a blob

Related

ASP.NET Core 6-7 Web API, Disable multipart/form-data model binding entirely (how to disable IFormFile bind?)

Im trying to create dotnet 7 webapi endpoint with streaming file upload but I always get an error that I cant overcome. I'm Trying to use a library called UploadStream, Github page: https://github.com/ma1f/uploadstream
Error:
System.IO.IOException: Unexpected end of Stream, the content may have already been read by another component.
at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync(Memory1 buffer, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool1 bytePool, Nullable1 limit, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.MultipartReader.ReadNextSectionAsync(CancellationToken cancellationToken) at Microsoft.AspNetCore.Http.Features.FormFeature.InnerReadFormAsync(CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormFileModelBinder.GetFormFilesAsync(String modelName, ModelBindingContext bindingContext, ICollection1 postedFiles)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FormFileModelBinder.BindModelAsync(ModelBindingContext bindingContext)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder.BindPropertyAsync(ModelBindingContext bindingContext, ModelMetadata property, IModelBinder propertyBinder, String fieldName, String modelName)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder.BindPropertiesAsync(ModelBindingContext bindingContext, Int32 propertyData, IReadOnlyList`1 boundProperties)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder.BindModelCoreAsync(ModelBindingContext bindingContext, Int32 propertyData)
It happens on line 31 in ControllerExtensions.cs with the method controller.TryUpdateModelAsync<T>(model, prefix: "", valueProvider : form);
Controller Code:
[HttpPost]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadPresentationV1()
{
byte[] buffer = new byte[1024 * 100];
List<IFormFile> files = new List<IFormFile>();
var model = await this.StreamFiles<UploadPresentationCommand>(async x =>
{
using (var stream = x.OpenReadStream())
while (await stream.ReadAsync(buffer, 0, buffer.Length) > 0) ;
files.Add(x);
});
return Ok("");
}
Model UploadPresentationCommand:
public class UploadPresentationCommand
{
[Required]
public string Name { get; set; }
[Required]
public string PresentationContent { get; set; }
public List<IFormFile> Images { get; set; }
}
I tried to use a disable form model binding attribute what I found in the microsoft documentation:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var factories = context.ValueProviderFactories;
factories.RemoveType<FormValueProviderFactory>();
factories.RemoveType<FormFileValueProviderFactory>();
factories.RemoveType<JQueryFormValueProviderFactory>();
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
What I found out, somehow even with this attribute the List<IFormFile> Images gets binded from the request to the model (For example if I specify it in the endpoint parameter like that [FromForm] UploadPresentationCommand uploadPresentationCommand, The files are binded, but the other two properties are not, so I assume that this is the root of the problem and I dont know how to disable this type of binding entirely, also im not sure if it could help.

How to tell Entity Framework that my ID column is auto-incremented (AspNet Core 2.0 + PostgreSQL)?

Code is simple.
Tag.cs entity:
public partial class Tag
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
HomeController.cs class:
public async Task<IActionResult> Index()
{
tagRepository.Insert(new Tag
{
Name = "name",
Description = "description"
});
await UnitOfWork.SaveChangesAsync(); // calls dbContext.SaveChangesAsync()
return View();
}
TagRepository.cs class:
// Context it's a usual DBContext injected via Repository's constructor
public virtual void Insert(TEntity item)
=> Context.Entry(item).State = EntityState.Added;
Tag table was created by running:
CREATE TABLE Tag (
ID SERIAL PRIMARY KEY,
Name text NOT NULL,
Description text NULL
);
When run my application I get an error:
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
Failed executing DbCommand (28ms) [Parameters=[#p0='?', #p1='?', #p2='?'], CommandType='Text', CommandTimeout='30']
INSERT INTO "tag" ("id", "description", "name")
VALUES (#p0, #p1, #p2);
Npgsql.PostgresException (0x80004005): 23505: duplicate key value violates unique constraint "tag_pkey"
at Npgsql.NpgsqlConnector.<DoReadMessage>d__157.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
at Npgsql.NpgsqlConnector.<ReadMessage>d__156.MoveNext()
As you can see Entity Framework tries to send id=0 value to the DB, but there is already a record with id=0 in my DB and that's why it throws duplicate key error.
I didn't find any answer so far and my question is: how can I get rid of this error and tell Entity Framework that my id column is auto-incremented and there is no need to update it?
You have to use here "ValueGenerationOnAdd()". As the issue you are getting is already reported on GitHub. Please find the below link.
https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/73
You can find more info regarding Generated Value pattern from following link.
Value generated on add
public classs SampleContext:DBContext{
public DbSet<Tag> Tag { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder){
modelBuilder.Entity<Tag>()
.Property(p => p.ID)
.ValueGeneratedOnAdd();
}
public class Tag{
public int Id { get; set; }
public string Name { get; set; }
public string Description{get;set;}
}
}
Source:- https://www.learnentityframeworkcore.com/configuration/fluent-api/valuegeneratedonadd-method
Hope this will help
According to the Postgre SQL docs here is an example which shows how to achieve the desired result:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().Property(b => b.Id).UseIdentityAlwaysColumn();
After a lot of wasted time on research I've solved it absolutely unexpected. Actually, the solution to my problem lies on the surface, because the problem is not in EF and not in it's stuff. In my case it was SEQUENCE. I mean, involved table has serial column and related sequence just was changed by some side-effect. In another words - sequence was restarted from 1 and at the same time the table is already having values with 1, 2, 3 ... etc. That's why postgres throws 'duplicate key' error. So, the solution is:
ALTER SEQUENCE "your_table_seq" RESTART WITH your_value;

WCF callback occurs error when serialize

I am programming a Azure WCF application.
A datacontract defined as below:
[DataContract]
public class UserInfo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int UserID { get; set; }
[DataMember]
public bool IsOnline { get; set; }
}
then I define a datacontract in my WCF service:
[DataContract(Name="UserInfo")]
public class ServiceUserInfo : UserInfo
{
[IgnoreDataMember]
public ICallback Callback { get; set; }
}
Then in the service contract, it will callback to client, the method as below
private void NoticeUsers(UserInfo currentuser)
{
var users = UserManager.GetAllActiveUsers();
foreach (var user in users)
{
if (user.UserName == currentuser.UserName)
continue;
user.Callback.UpdateUserList(currentuser);
}
}
Actually I pass a ServiceUserInfo object as parameter to the NoticeUsers method. Then an error will occurs as below:
There was an error while trying to serialize parameter http://tempuri.org/:user. The InnerException message was 'Type 'WCFServiceWebRole.ServiceUserInfo' with data contract name 'UserInfo:http://schemas.datacontract.org/2004/07/WCFServiceWebRole' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
I am not able to find solution for this issue.Please help.
I think I have found the root cause of the issue, however I do not know why.
The problem is caused by the Namespace attribute of the Service contract.
I didn't set the namespace of my service contract interface and data contract interface. I thought it would be set by default and it won't cause any problem. But actually the issue of this thread is caused by the Namespace attribute. I set a Namespace attribute for both service contract and data contract, of course the same namespace, then it worked. The problem never happens again.
However, I do not know why it caused this issue. If I do not set Namespace, it will be a default value of "http://tempuri.org", isn't it?

toList() System.InvalidCastException was unhandled by user code

I have written a WCF service using LINQ to SQL (using the following article at codeporject). I am facing the invalid cast exception when i invoke the .ToList() method of an object after i have already made a wcf function call of the same service against the same database.
The exception is:
System.InvalidCastException was unhandled by user code
Message=Specified cast is not valid.
Source=System.Data
StackTrace:
at System.Data.SqlClient.SqlBuffer.get_Int64()
at System.Data.SqlClient.SqlDataReader.GetInt64(Int32 i)
at Read_Command(ObjectMaterializer`1 )
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at SystemsManager.ACS.GetCommands(Int64 agentId) in E:\Projects\SystemsManager\AgentControlService\ACS.svc.cs:line 167
at SyncInvokeGetCommands(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
InnerException:
The specific line i am having issue is with the ToList() method
public List<Command> GetCommands(long agentId)
{
var cmd = from command in db.Command where (command.AgentId == agentId) select command;
return cmd.ToList();
}
When debugging, the return statment throws exception. When view the value of cmd.ToList() in Quick Watch of VS 2010, the exception is shown.
Now the strangest thing is: Pressing "Re-Evaluate" button a couple of times changes the exception to required object list in Quick watch. Infact i have to press "Re-evaluate" at least three times.
I have generated client using svcutil tool after my most recent changes to the service/database.
I am calling the method using the following code from a windows service:
var agent = client.GetAgentByIpAddress(myIPAddress);
client.Close();
if (agent != null)
{
if (agent.AgentId != -1)
{
client = new ACSClient();
var command = client.GetCommands(agent.AgentId);
.....
Here is the model of Command in the interface of the wcf service.
[DataContract]
[Table(Name = "Command")]
public class Command
{
[DataMember, Column(IsPrimaryKey = true, Name = "Command_Id", AutoSync = AutoSync.OnInsert, IsDbGenerated = true, DbType = "Bigint NOT null identity")]
public long CommandId { get; set; }
[DataMember, Column(Name = "Agent_Id")]
public long AgentId { get; set; }
[DataMember, Column(Name = "Name")]
public string CommandName { get; set; }
[DataMember, Column(Name = "Paramters")]
public string CommandParamters { get; set; }
[DataMember, Column(Name = "Is_Fetched")]
public bool IsFectched { get; set; }
[DataMember, Column(Name = "Status")]
public long Status { get; set; }
[DataMember, Column(Name = "Response")]
public string Response { get; set; }
[DataMember, Column(Name = "Created")]
public DateTime Created { get; set; }
[DataMember, Column(Name = "Last_Modified")]
public DateTime LastModified { get; set; }
[DataMember, Column(Name = "Is_Enabled")]
public bool IsEnabled { get; set; }
}
Important thing is: My database file is located in AppData folder of the WCF service. I am using only one instance of db object (refer to 1st code block above) throughout my wcf service and i am wondering if this could be cause of the problem???
Also, i have called a couple of similar method of this very same wcf service from a desktop application but i have not faced any such issue.
Please help. if more details are needed, please state so.. The only thing that can come to mind is that perhaps the database is in use and when another connection is made to the database by the service, it fails. and retrying it a couple of times using the Quick Watch > Re-evaluate button displays the required values in the watch window without throwing any error.
Kindly help on this one. Quick responses are highly appreciated.
Thanks.
Steve
Never mind guys. I solved it.
For anyone else who is getting invalid cast exception, here is the solution.
The error only occurs when actual class model is different that the database.
If you have created the class model by hand coding it, the you must match each column name of the table to your corresponding class. LINQ to sql encounters error when it cannot convert a database type to .Net type and throws invalid cast exception.
So in most cases, either fixing the error manually in the model class or regenerating the class will solve the problem.

nservicebus message serialization

I would like to use a base message class like:
[Serializable]
public abstract class MessageBase : IMessage
{
public Guid MessageID { get; private set; }
public DateTime UtcDateTime { get; private set; }
protected MessageBase()
{
UtcDateTime = DateTime.UtcNow;
MessageID = Guid.NewGuid();
}
public override string ToString()
{
return string.Format("{0} MessageID={1}, UtcDate={2}", GetType().FullName, MessageID, UtcDateTime);
}
}
New messages will be created by subclassing from this base class. Here is the problem I observed. When I publish a message, I see that the message id and datetime is different when it is handled.
What am I missing?
I know you want to declare MessageID and UtcDateTime with private setters so that someone down the line can't change it, but in doing so, you prevent the serializer from re-applying those values when the message is reconstructed at the receiver.
What is happening is that the serializer instantiates a new instance of your message type, and your two properties are initialized to UtcNow and NewGuid(), and then aren't overridden from the message. This is why they appear different.
If you remove the private keyword from the property declaration, you should get the behavior you are expecting.
However, instead of baking your own tracking mechanisms like this, you should at least (assuming you have injected an IBus into your handler) take a look at Bus.CurrentMessageContext, which contains an "Id" property for the message being handled (string, not Guid) and a Headers collection. I'm not 100% certain, but if you inspect the headers there is probably some indication of the original send time in there.