VB - ensuring a text file is written to and closed before opening to read from it

I'd like to read the report or text file generated below (3rd from last line) into a textbox:
        Dim config As New MarketplaceWebServiceConfig
        config.ServiceURL = "https://mws.amazonservices.co.uk"
        Dim myClient As New MarketplaceWebServiceClient(AccessKey, SecretKey, ApplicationName, ApplicationVersion, config)
        Dim myRequest As New GetReportRequest
        myRequest.Merchant = SellerID
        myRequest.ReportId = reportId
        myRequest.Report = File.Open("C:\\report\" + reportId.ToString + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)
        Dim myResponse As New GetReportResponse
        myResponse = myClient.GetReport(myRequest)

Open in new window


If I add a final line:
myTextbox.text = File.ReadAllText("C:\\report\" + reportId.ToString + ".txt")

Open in new window

I get "The process cannot access the file "xxx" because it is being used by another process."

What do I need to do to ensure the file is written to and closed before attempting to read from it?
LVL 1
BeamsonAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Joe FulginitiNetwork EngineerCommented:
For starters, you should place your code in a try statement:

try
       Dim config As New MarketplaceWebServiceConfig
        config.ServiceURL = "https://mws.amazonservices.co.uk"
        Dim myClient As New MarketplaceWebServiceClient(AccessKey, SecretKey, ApplicationName, ApplicationVersion, config)
        Dim myRequest As New GetReportRequest
        myRequest.Merchant = SellerID
        myRequest.ReportId = reportId
        myRequest.Report = File.Open("C:\\report\" + reportId.ToString + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)
        Dim myResponse As New GetReportResponse
        myResponse = myClient.GetReport(myRequest)
catch ex as exception
        response.write("Failed to access file and got the following error: " + ex.message)
        'or some other type of code to handle the error.
end try

Open in new window


Since it looks like this is a web app, you should be writing this to the database and then perhaps write another program that pulls the information from the database and writes it to a file.  The program can be a console program that gets called from the task scheduler.  This will prevent more than one program from accessing files at the same time.
0
Joe FulginitiNetwork EngineerCommented:
Something like this is what I have been looking at for a similar project.  Reviews are good and you can just plug it into the router.

https://www.amazon.com/NETGEAR-LTE-Modem-Broadband-Connection/dp/B01N5ASNTE/ref=sr_1_2?ie=UTF8&qid=1510678769&sr=8-2&keywords=cellular+router
0
Fabrice LambertFabrice LambertCommented:
Hi,

In your code, make sur that any opened file is properly closed, even if errors happen (check error handlers).

But, if the file is opened by an external process, there isn't much you can do, beside handling and reporting the error, so the user can try again.

Somes might say that you can try to read it again after a little amount of time, but that's running the risk of locking your application forever (what if the file is locked bc of a crash ? Or was never properly closed ?)
0
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

BeamsonAuthor Commented:
Okay, some mixed suggestions there.

Joe: that's a fair point - I've omitted the Try Catch in my sample code for simplicity (I have it in my main code).
However, this part of the code works fine, without error.
It is only the addition of an attempt to read back from the file immediately afterwards that fails.
Your second comment just seemed to be a link to buy a router!

Fabrice: there should be no external process which accesses the file.  I agree any open file should be closed.  My question is about how I wait for the action of writing to the file to end before closing the file and attempting to read the file back.
I could do a wait/retry loop but is there some other way of waiting for the previous task (writing to the file) to complete before moving on to the next file open / read commands?
0
Joe FulginitiNetwork EngineerCommented:
Sorry, I had a lot of tabs open and the link was for another post.  I deleted it.
0
Fernando SotoRetiredCommented:
Hi Beamson;

This line of code opens the file for read/write and assigns the return a FileStream to myRequest.Report at which point you relinquish control of the open file to the object myRequest. In that object it should close the file when it is finished using it so that calls to read it from other parts of your app does not fail.
myRequest.Report = File.Open("C:\\report\" + reportId.ToString + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)

Open in new window

I assume that after this line of code is executed the myRequest object has completed using the file and should have closed it.
 myResponse = myClient.GetReport(myRequest)

Open in new window

0
BeamsonAuthor Commented:
should have closed it

I agree, the file should be closed but for some reason it is not.
If I debug the sub with a long system.threading value (few minutes) and then try to access the textfile I get the same problem.

If I debug it with no system.threading value, let is fail, then open the same file from another subroutine, it opens fine.  It is as though the process that creates and writes to the file is not releasing the file once written to.

If I separate the writing and reading back of the text file into two separate subs and run them in the same debugging session, they also fail with the same error when reading back.  I feel as though I need to explicitly release the file somewhere but don't know where or how.
0
Fernando SotoRetiredCommented:
Please post the class myRequest here.

Thanks
0
BeamsonAuthor Commented:
 Dim myRequest As New GetReportRequest

Open in new window


myRequest.Merchant = SellerID
        myRequest.ReportId = reportId
        myRequest.Report = File.Open(MyPath+ reportId.ToString + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite)

Open in new window


Imports System
Imports System.IO
Imports System.Xml.Serialization
Imports MarketplaceWebService.Attributes

Namespace MarketplaceWebService.Model
    <MarketplaceWebService(RequestType:=RequestType.DEFAULT, ResponseType:=ResponseType.STREAMING)> <XmlRoot([Namespace]:="http://mws.amazonaws.com/doc/2009-01-01/", IsNullable:=False)> <XmlType([Namespace]:="http://mws.amazonaws.com/doc/2009-01-01/")>
    Public Class GetReportRequest
        Public Sub New()

        <Obsolete("Not used anymore. MWS ignores this parameter, but it is left in here for backwards compatibility.")> <XmlElement(ElementName:="Marketplace")>
        Public Property Marketplace As String
        <XmlElement(ElementName:="Merchant")>
        Public Property Merchant As String
        <XmlElement(ElementName:="MWSAuthToken")>
        Public Property MWSAuthToken As String
        <MarketplaceWebServiceStream(StreamType:=StreamType.RECEIVE_STREAM)>
        Public Property Report As Stream
        <XmlElement(ElementName:="ReportId")>
        Public Property ReportId As String

        <Obsolete("Not used anymore. MWS ignores this parameter, but it is left in here for backwards compatibility.")>
        Public Function IsSetMarketplace() As Boolean
        Public Function IsSetMerchant() As Boolean
        Public Function IsSetMWSAuthToken() As Boolean
        Public Function IsSetReport() As Boolean
        Public Function IsSetReportId() As Boolean
        <Obsolete("Not used anymore. MWS ignores this parameter, but it is left in here for backwards compatibility.")>
        Public Function WithMarketplace(marketplace As String) As GetReportRequest
        Public Function WithMerchant(merchant As String) As GetReportRequest
        Public Function WithMWSAuthToken(mwsAuthToken As String) As GetReportRequest
        Public Function WithReport(report As Stream) As GetReportRequest
        Public Function WithReportId(reportId As String) As GetReportRequest
    End Class
End Namespace

Open in new window

0
Fernando SotoRetiredCommented:
Where is the implementation for this?
Public Function WithReport(report As Stream) As GetReportRequest

Open in new window

0
BeamsonAuthor Commented:
Not sure how to answer that question.  The classes are provided as part of one of Amazon's dlls.  Will take a look tomorrow and see what I can find when I'm at my desk.
0
Fernando SotoRetiredCommented:
Hi Beamson;

It seems that Amazon is not closing the file so try the following code modification after the line shown.
myResponse = myClient.GetReport(myRequest)
'' Add these two lines after the above line
myRequest.Report.Close()
myRequest.Report.Dispose()

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
BeamsonAuthor Commented:
That did the trick!

I'd tried variations of that but was focusing on closing the response objects rather than the request ones.
Your way worked immediately.

Thanks for all of your help!
0
Fernando SotoRetiredCommented:
Not a problem Beamson, glad I was able to help.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.